docker 发布的方式为实现devops(自动化运维,需要配置 代码管理工具如git的hook来实现提交编译、打包、发布等一系列事件控制)提供了诸多方便,辅助于shell脚本可以很好的配合起来。

docker镜像可以通过自动化编译,也可以通过导入镜像的方式来获得。

本文的题目叫:shell脚本构建docker 半自动化编译打包发布,因为我这里还没跟代码管理关联起来。

shell脚本不同实现

导入镜像方式(镜像文件rtvsweb-publish.tar):

构建发布方式(依靠dockerfile来构建):

shell docker构建发布脚本工具核心install.sh

#! /bin/bash
##file:rtvs.sh
##company:cvnavi.com
##author:pengjunlin
echo "当前执行文件......$0"
##################################变量定义##################################
docker_image_is_match_tar_file="false"
docker_rtvsweb_container_name="rtvsweb-publish"
docker_rtvsweb_new_version=""
docker_rtvsweb_first_version=1
docker_rtvsweb_second_version=0
docker_rtvsweb_third_version=0
docker_rtvsweb_version_tag=""
docker_container_temp_host=""
db_redis_connection_string=""
db_mysql_connection_string=""
db_mysql_host=""
master_lan_ip=""
system_allow_to_set="false"
###################################函数定义#######################################
function init_files()
{
# 创建rtvs目录
if [[ ! -d "/usr/local/rtvs" ]]; then
echo "创建容器映射路径.... /usr/local/rtvs"
mkdir /usr/local/rtvs
fi
# 复制versionconfig.xml(第一次做完全复制,若有变动需要手动修改)
if [[ -f "./versionconfig.xml" ]]; then
if [[ ! -f "/usr/local/rtvs/versionconfig.xml" ]]; then
echo "拷贝一份xml配置文件: ./versionconfig.xml /usr/local/rtvs/versionconfig.xml"
cp versionconfig.xml /usr/local/rtvs/versionconfig.xml
fi
else
echo "缺少./versionconfig.xml文件...已退出安装!"
exit
fi
# 复制settingconfig.xml(第一次做完全复制,若有变动需要手动修改)
if [[ -f "./settingconfig.xml" ]]; then
if [[ ! -f "/usr/local/rtvs/settingconfig.xml" ]]; then
echo "拷贝一份xml配置文件: ./settingconfig.xml /usr/local/rtvs/settingconfig.xml"
cp settingconfig.xml /usr/local/rtvs/settingconfig.xml
fi
else
echo "缺少./settingconfig.xml文件...已退出安装!"
exit
fi
# 复制log4.config(第一次做完全复制,若有变动需要手动修改)
if [[ -f "./log4.config" ]]; then
if [[ ! -f "/usr/local/rtvs/log4.config" ]]; then
echo "拷贝一份日志配置文件: ./log4.config /usr/local/rtvs/log4.config"
cp log4.config /usr/local/rtvs/log4.config
fi
else
echo "缺少./log4.config文件...已退出安装!"
exit
fi
}
function mysql_create_table()
{
if [[ -f "./mysql_create_table.sh" ]]; then
echo "数据库脚本赋值权限......"
# 为执行文件添加权限
chmod a+x mysql_create_table.sh
else
echo "缺少./mysql_create_table.sh文件...已退出安装!"
exit
fi
# 执行mysql数据库表创建
./mysql_create_table.sh
if [[ $? -eq 0 ]]; then
echo "./mysql_docker_install.sh 执行完成!"
else
exit
fi
}
function docker_install()
{
echo "检查docker......"
docker -v
if [ $? -eq 0 ]; then
echo "检查到docker已安装!"
else
echo "安装docker环境..."
curl -ssl https://get.daocloud.io/docker | sh
echo "安装docker环境...安装完成!"
fi
# 创建公用网络==bridge模式
#docker network create share_network
}
function mysql_install(){
install_type=$1
if [[ "$install_type" == "by_local_mysql_installer" ]]; then
#statements
echo "暂不支持wget本地下载安装,已退出!"
exit 1
fi
if [[ "$install_type" == "by_docker_mysql_installer" ]]; then
#statements
docker_mysql_install
fi
if [[ "$install_type" == "by_smart_installer" ]]; then
#statements
if [[ `netstat -lanp|grep tcp|grep 3306|wc -l` == 1 ]]; then
echo "检测到mysql已在本机安装!"
# 打印一下mysql版本
echo "检测到mysql版本:"
mysql --version
# 执行创建mysql数据库脚本
mysql_create_table
if [[ $? -eq 0 ]]; then
echo "本地mysql脚本初始化完成!"
else
echo "本地mysql脚本初始化失败!"
exit 1
fi
db_mysql_host="localhost"
else
docker_mysql_install
fi
fi
}
function docker_mysql_install(){
echo "安装docker mysql环境..."
if [[ -f "./docker_mysql_install.sh" ]]; then
if [[ -f "./docker_mysql_create_table.sh" ]]; then
echo "拷贝一份容器执行文件: ./docker_mysql_create_table.sh /usr/local/docker_mysql_create_table.sh"
cp docker_mysql_create_table.sh /usr/local/docker_mysql_create_table.sh
else
echo "缺少./docker_mysql_create_table.sh文件...已退出安装!"
exit 1
fi
# 为执行文件添加权限
chmod a+x docker_mysql_install.sh
# dokcer方式安装mysql
./docker_mysql_install.sh
if [[ $? -eq 0 ]]; then
echo "./docker_mysql_install.sh 执行完成!"
# 休10秒钟
echo "休眠等待10s,等待docker执行完成......"
sleep 10s
# 测试打印mysql信息
print_docker_mysql_info
else
echo "./docker_mysql_install.sh 执行过程中出现错误,已退出安装!"
exit 1
fi
else
echo "缺少./docker_mysql_install.sh文件...已退出安装!"
exit 1
fi
}
function docker_container_ip() {
docker_container_temp_host=` docker inspect --format '{{ .networksettings.ipaddress }}' $1`
}
function init_docker_master_ip(){
out=0
for i in `ip a |grep inet[^6]|grep -e -o '([0-9]{1,3}\.){3}[0-9]{1,3}'`; do
old_ifs="$ifs" 
ifs="." 
arr=($i) 
ifs="$old_ifs" 
for s in ${arr[@]} ;do 
if [[ $s -eq "192" ]]; then
echo "$i" 
master_lan_ip=$i
out=1
break
fi
done
if [[ $out -eq 1 ]]; then
break
fi
done
}
function print_docker_mysql_info()
{
echo "脚本执行mysql信息验证:..."
if [[ -f "./docker_mysql_validator.sh" ]]; then
echo "拷贝一份容器执行文件: ./docker_mysql_validator.sh /usr/local/docker_mysql_validator.sh"
cp docker_mysql_validator.sh /usr/local/docker_mysql_validator.sh
else
echo "缺少./docker_mysql_validator.sh文件...已退出安装!"
exit
fi
# 映射copy文件路径到docker容器
docker cp /usr/local/docker_mysql_validator.sh mysql5.7:/usr/local/docker_mysql_validator.sh
docker exec -it mysql5.7 /bin/bash -c "sh /usr/local/docker_mysql_validator.sh"
if [[ $? -eq 0 ]]; then
echo "./docker_mysql_validator.sh 执行完成!"
echo "mysql容器host:"
docker_container_ip mysql5.7 
echo "当前mysql5.7实例ip=$docker_container_temp_host"
#echo "mysql容器network 相关信息:"
#docker network inspect share_network
#echo "mysql容器link相关信息:"
#cat /etc/hosts
else
echo "./docker_mysql_validator.sh 执行过程中出现错误,已退出安装!"
exit
fi
#link 访问方式
db_mysql_host="mysql5.7"
}
function destory_docker_service()
{
# 停止容器
for i in [ `docker ps ` ]; do
if [[ "$i" == "rtvsweb-publish" ]]; then
echo "尝试停止$docker_rtvsweb_container_name容器..."
docker stop $docker_rtvsweb_container_name
fi
done
# 删除容器
for i in [ `docker ps -a` ]; do
if [[ "$i" == "rtvsweb-publish" ]]; then
echo "尝试删除$docker_rtvsweb_container_name容器..."
docker rm $docker_rtvsweb_container_name
fi
done
}
function docker_build_image()
{
# 清理容器(保留历史构建的镜像)
destory_docker_service
if [[ $? -eq 0 ]]; then
echo "应用服务容器和镜像已处理,配置文件已完成复制!"
else
exit 1
fi
echo "docker镜像构建......cmd:(docker build -t rtvsweb:$docker_rtvsweb_new_version .)"
docker build -t rtvsweb:$docker_rtvsweb_new_version .
# 判断是否有镜像,存在时创建相应的容器实例
for i in [ `docker images` ]; do
#statements
if [[ "$i" == "$docker_rtvsweb_new_version" ]]; then
docker_image_is_match_tar_file="true"
echo "已经找到最新构建的镜像!"
run_docker_service_image
break
fi
done
if [[ $docker_image_is_match_tar_file == "false" ]]; then
echo "构建镜像未匹配到最新版本,已退出安装!"
exit 1
fi
echo "构建后的docker images镜像列表:"
docker images
echo "当前正在运行的docker容器实例列表:"
docker ps
}
function run_docker_service_image()
{
echo "正在启动docker 服务容器......"
# run 的参数设置参考vs项目启动的设置--privileged=true 获取管理员权限
# ===bridge 桥接模式
#docker run -it --name=$docker_rtvsweb_container_name --net="bridge" --dns 8.8.8.8 --network share_network --network-alias $4 -v /usr/local/rtvs/error_log:/app/error_log -v /usr/local/rtvs/log_file:/app/logfile -v /usr/local/rtvs/mydata:/mydata -v /usr/local/rtvs/videocache:/myvideo -v /usr/local/rtvs/settingconfig.xml:/app/settingconfig.xml -p 38067:80 -p 44383:443 -p 18000:18000 -p 18002:18002 -p 19700:19700 -p 19702:19702 -p 19703:19703 -d $docker_rtvsweb_image_tag_name
if [[ $db_mysql_host == "mysql5.7" ]]; then
# ===link 链接模式
echo "rtvsweb--容器运行---链接模式"
docker run -it --name $docker_rtvsweb_container_name --privileged=true --link mysql5.7:mysql5.7 -v /usr/local/rtvs:/mydata -e mydatapath=/mydata -p 38067:80 -p 44383:443 -p 18000:18000 -p 18002:18002 -p 19700-19719:19700-19719 -p 30888-30889:30888-30889 -d rtvsweb:$docker_rtvsweb_new_version
else
# ===普通模式
echo "rtvsweb--容器运行---普通模式"
docker run -it --name $docker_rtvsweb_container_name --privileged=true -v /usr/local/rtvs:/mydata -e mydatapath=/mydata -p 38067:80 -p 44383:443 -p 18000:18000 -p 18002:18002 -p 19700-19719:19700-19719 -p 30888-30889:30888-30889 -d rtvsweb:$docker_rtvsweb_new_version
fi
}
####################工具类和流程定制################################
function editxml()
{
val=`echo ${@:3}`
echo "正在修改xml文件:$1...."
echo "正在修改xml文件:[0]=$1,[1]=$2,[2]=$val"
echo "xml文件$2标签 value=$val"
sed -i "s/<$2>.*<\/$2>/<$2>${val}<\/$2></g" $1
}
function init_mysql_conn()
{
if [[ "$db_mysql_host" == "localhost" ]]; then
mysql="database=filecache;data source=$master_lan_ip;port=3366;user id=rtvsweb;password=rtvs2018;charset=utf8;pooling=true"
sed -i "s/<mysqlconnectionstring>.*<\/mysqlconnectionstring>/<mysqlconnectionstring>$mysql<\/mysqlconnectionstring>/g" /usr/local/rtvs/settingconfig.xml
db_mysql_connection_string=`grep -e -o -e '<mysqlconnectionstring>.+</mysqlconnectionstring>' /usr/local/rtvs/settingconfig.xml | sed 's/<mysqlconnectionstring>//g'|sed 's/<\/mysqlconnectionstring>//g'`
else
mysql="database=filecache;data source=mysql5.7;port=3306;user id=rtvsweb;password=rtvs2018;charset=utf8;pooling=true"
sed -i "s/<mysqlconnectionstring>.*<\/mysqlconnectionstring>/<mysqlconnectionstring>$mysql<\/mysqlconnectionstring>/g" /usr/local/rtvs/settingconfig.xml
db_mysql_connection_string=`grep -e -o -e '<mysqlconnectionstring>.+</mysqlconnectionstring>' /usr/local/rtvs/settingconfig.xml | sed 's/<mysqlconnectionstring>//g'|sed 's/<\/mysqlconnectionstring>//g'`
fi
} 
function editspecificconfig()
{
init_mysql_conn
echo "获取/usr/local/rtvs/settingconfig.xml信息..."
cat /usr/local/rtvs/settingconfig.xml
# 判断是否可以设置
if [[ "$system_allow_to_set" == "true" ]]; then
read -p ">>>是否修改redis配置连接字符串?y/n:" ans
echo "$ans"
if [[ "$ans" == "y" ]]; then
read -p "请输入redis配置连接字符串:" redis
echo "新的redis连接字符串:$redis"
sed -i "s/<redisexchangehosts>.*<\/redisexchangehosts>/<redisexchangehosts>$redis<\/redisexchangehosts>/g" /usr/local/rtvs/settingconfig.xml
db_redis_connection_string=`grep -e -o -e '<redisexchangehosts>.+</redisexchangehosts>' /usr/local/rtvs/settingconfig.xml | sed 's/<redisexchangehosts>//g'|sed 's/<\/redisexchangehosts>//g'`
echo "获取已修改的redis配置连接字符串...redisexchangehosts=$db_redis_connection_string"
fi
read -p ">>>是否修改mysql配置连接字符串?y/n:" ans
echo "$ans"
if [[ "$ans" == "y" ]]; then
read -p "请输入mysql配置连接字符串:" mysql
echo "新的mysql连接字符串:$mysql"
sed -i "s/<mysqlconnectionstring>.*<\/mysqlconnectionstring>/<mysqlconnectionstring>$mysql<\/mysqlconnectionstring>/g" /usr/local/rtvs/settingconfig.xml
db_mysql_connection_string=`grep -e -o -e '<mysqlconnectionstring>.+</mysqlconnectionstring>' /usr/local/rtvs/settingconfig.xml | sed 's/<mysqlconnectionstring>//g'|sed 's/<\/mysqlconnectionstring>//g'`
echo "获取已修改的mysql配置连接字符串...mysqlconnectionstring=$db_mysql_connection_string"
fi
fi
}
function remoteredisandmysqlconfig()
{
echo "获取/usr/local/rtvs/settingconfig.xml信息..."
cat /usr/local/rtvs/settingconfig.xml
# 设置redis连接字符串
read -p "是否修改redis配置连接字符串?y/n:" ans
echo "$ans"
if [[ "$ans" == "y" ]]; then
read -p "请输入redis连接字符串:" redis
echo "新的redis连接字符串:$redis"
sed -i "s/<redisexchangehosts>.*<\/redisexchangehosts>/<redisexchangehosts>$redis<\/redisexchangehosts>/g" /usr/local/rtvs/settingconfig.xml
db_redis_connection_string=`grep -e -o -e '<redisexchangehosts>.+</redisexchangehosts>' /usr/local/rtvs/settingconfig.xml | sed 's/<redisexchangehosts>//g'|sed 's/<\/redisexchangehosts>//g'`
echo "获取已修改的redis配置连接字符串...redisexchangehosts=$db_redis_connection_string"
fi
read -p "是否修改mysql配置连接字符串?y/n:" ans
echo "$ans"
if [[ "$ans" == "y" ]]; then
read -p "请输入mysql连接字符串:" mysql
echo "新的mysql连接字符串:$mysql"
sed -i "s/<mysqlconnectionstring>.*<\/mysqlconnectionstring>/<mysqlconnectionstring>$mysql<\/mysqlconnectionstring>/g" /usr/local/rtvs/settingconfig.xml
db_mysql_connection_string=`grep -e -o -e '<mysqlconnectionstring>.+</mysqlconnectionstring>' /usr/local/rtvs/settingconfig.xml | sed 's/<mysqlconnectionstring>//g'|sed 's/<\/mysqlconnectionstring>//g'`
echo "获取已修改的mysql配置连接字符串...mysqlconnectionstring=$db_mysql_connection_string"
fi
}
function help()
{
echo "*******************************************"
echo "*********    调用方法说明  ************"
echo "*******************************************"
echo "查看核心配置文件:cat ./settingconfig.xml"
echo "帮助方法说明:sh ./install.sh help"
echo "修改redis和mysql连接字符串:sh ./install.sh editxml [xmlfilepath] [tag] ['value'] "
echo "********************************************"
echo "*********    快速定制安装  *************"
echo "********************************************"
echo "1、执行本地mysql安装(wget下载文件安装...比较费时): sh ./install.sh by_local_mysql_installer"
echo "2、执行docker mysql安装 : sh ./install.sh by_docker_mysql_installer"
echo "3、智能检测决定mysql安装方式(如果本机已有mysql则直接使用): sh ./install.sh by_smart_installer"
echo "4、简化安装只需要给出redis和mysql连接字符串即可(极简方式): sh ./install.sh by_simple_installer"
echo "说明:\r 以上4种方式已包含了docker应用的安装!"
}
function completed()
{
echo "******************安装结果:*****************"
# bridge 桥接模式
#echo "network实例, share_network相关容器信息:"
#docker network inspect share_network
version_step=1
# 记录下一次版本号
if [[ "$docker_rtvsweb_version_tag" == "versionfirst" ]]; then
docker_rtvsweb_first_version=$((docker_rtvsweb_first_version+version_step))
sed -i "s/<versionfirst>.*<\/versionfirst>/<versionfirst>$docker_rtvsweb_first_version<\/versionfirst>/g" /usr/local/rtvs/versionconfig.xml
sed -i "s/<versionsecond>.*<\/versionsecond>/<versionsecond>0<\/versionsecond>/g" /usr/local/rtvs/versionconfig.xml
sed -i "s/<versionthird>.*<\/versionthird>/<versionthird>0<\/versionthird>/g" /usr/local/rtvs/versionconfig.xml
fi
if [[ "$docker_rtvsweb_version_tag" == "versionsecond" ]]; then
docker_rtvsweb_second_version=$((docker_rtvsweb_second_version+version_step))
sed -i "s/<versionsecond>.*<\/versionsecond>/<versionsecond>$docker_rtvsweb_second_version<\/versionsecond>/g" /usr/local/rtvs/versionconfig.xml
sed -i "s/<versionthird>.*<\/versionthird>/<versionthird>0<\/versionthird>/g" /usr/local/rtvs/versionconfig.xml
fi
if [[ "$docker_rtvsweb_version_tag" == "versionthird" ]]; then
docker_rtvsweb_third_version=$((docker_rtvsweb_third_version+version_step))
sed -i "s/<versionthird>.*<\/versionthird>/<versionthird>$docker_rtvsweb_third_version<\/versionthird>/g" /usr/local/rtvs/versionconfig.xml
fi
video_cache_path=`grep -e -o -e '<videocachepath>.+</videocachepath>' /usr/local/rtvs/settingconfig.xml | sed 's/<videocachepath>//g'|sed 's/<\/videocachepath>//g'`
db_redis_connection_string=`grep -e -o -e '<redisexchangehosts>.+</redisexchangehosts>' /usr/local/rtvs/settingconfig.xml | sed 's/<redisexchangehosts>//g'|sed 's/<\/redisexchangehosts>//g'`
db_mysql_connection_string=`grep -e -o -e '<mysqlconnectionstring>.+</mysqlconnectionstring>' /usr/local/rtvs/settingconfig.xml | sed 's/<mysqlconnectionstring>//g'|sed 's/<\/mysqlconnectionstring>//g'`
echo "redis连接字符串:$db_redis_connection_string"
echo "mysql连接字符串:$db_mysql_connection_string"
echo "默认视频缓存目录:$video_cache_path"
echo "正在运行的容器实例:"
docker ps
echo "容器对应的ip地址:"
docker_container_ip mysql5.7
if [[ "$docker_container_temp_host" != "" ]]; then
echo "mysql5.7   ---------------------$docker_container_temp_host" 
fi
docker_container_ip $docker_rtvsweb_container_name
echo "$docker_rtvsweb_container_name ---------------------$docker_container_temp_host"
echo "验证rtvs访问:curl http://cvtsp.com:38067/"
echo "******************安装完成!*****************"
}
function version_management()
{
docker_rtvsweb_first_version=`grep -e -o -e '<versionfirst>.+</versionfirst>' /usr/local/rtvs/versionconfig.xml | sed 's/<versionfirst>//g'|sed 's/<\/versionfirst>//g'`
docker_rtvsweb_second_version=`grep -e -o -e '<versionsecond>.+</versionsecond>' /usr/local/rtvs/versionconfig.xml | sed 's/<versionsecond>//g'|sed 's/<\/versionsecond>//g'`
docker_rtvsweb_third_version=`grep -e -o -e '<versionthird>.+</versionthird>' /usr/local/rtvs/versionconfig.xml | sed 's/<versionthird>//g'|sed 's/<\/versionthird>//g'`
docker_rtvsweb_version_tag=`grep -e -o -e '<upgradetag>.+</upgradetag>' /usr/local/rtvs/versionconfig.xml | sed 's/<upgradetag>//g'|sed 's/<\/upgradetag>//g'`
docker_rtvsweb_new_version="$docker_rtvsweb_first_version.$docker_rtvsweb_second_version.$docker_rtvsweb_third_version"
echo "当前rtvsweb版本:$docker_rtvsweb_new_version"
echo "当前rtvsweb版本升级格式:$docker_rtvsweb_version_tag"
}
function by_local_mysql_installer()
{
# docker 安装
docker_install
# mysql 安装及其脚本创建
mysql_install "by_local_mysql_installer"
# 镜像构建
if [[ $? -eq 0 ]]; then
docker_build_image
if [[ $? -eq 0 ]]; then
echo "镜像构建成功!"
else
echo "镜像构建失败!"
exit 
fi
else
exit
fi
# 修改镜像使用的路径和数据源
editspecificconfig
# 完成后输出
completed
}
function by_docker_mysql_installer()
{
# docker 安装
docker_install
# mysql 安装及其脚本创建
mysql_install "by_docker_mysql_installer"
# 镜像构建
if [[ $? -eq 0 ]]; then
docker_build_image
if [[ $? -eq 0 ]]; then
echo "镜像构建成功!"
else
echo "镜像构建失败!"
exit 
fi
else
exit
fi
# 修改镜像使用的路径和数据源
editspecificconfig
# 完成后输出
completed
}
function by_smart_installer()
{
# docker 安装
docker_install
# mysql 安装及其脚本创建
mysql_install "by_smart_installer"
# 镜像构建
if [[ $? -eq 0 ]]; then
docker_build_image
if [[ $? -eq 0 ]]; then
echo "镜像构建成功!"
else
echo "镜像构建失败!"
exit 
fi
else
exit
fi
# 修改镜像使用的路径和数据源
editspecificconfig
# 完成后输出
completed
}
function by_simple_installer()
{
# docker 安装
docker_install  
# 镜像构建
docker_build_image 
if [[ $? -eq 0 ]]; then
echo "镜像构建成功!"
else
echo "镜像构建失败!"
exit 
fi
# 修改镜像使用的路径和数据源
remoteredisandmysqlconfig
# 完成后输出
completed
} 
if [[ $# -gt 0 ]]; then
echo "安装所需文件检查...."
init_files
if [[ $? -eq 0 ]]; then
echo "安装docker服务的文件存在,验证通过!"
else
echo "安装docker服务的文件存在缺失,已退出安装!"
exit 
fi
echo "rtvsweb版本检查...."
version_management 
echo "获取本地局域网ip地址...."
init_docker_master_ip
echo "本地ip地址....master_lan_ip=$master_lan_ip"
#statements 
if [[ "$1" == "by_local_mysql_installer" ]]; then
#statements
by_local_mysql_installer 
fi
if [[ "$1" == "by_docker_mysql_installer" ]]; then
#statements
by_docker_mysql_installer 
fi
if [[ "$1" == "by_smart_installer" ]]; then
#statements
by_smart_installer 
fi	
if [[ "$1" == "by_simple_installer" ]]; then
#statements
by_simple_installer 
fi	
if [[ "$1" == "editxml" ]]; then
if [[ $# -eq 4 ]]; then
#statements
editxml $2 $3 $4
else
echo "editxml参数个数不匹配!"
fi
fi	
if [[ "$1" == "help" ]]; then
#statements
help
fi	
else
help
fi

整体设计实现思路

1、docker环境准备和安装

2、mysql环境准备和安装

3、docker的知识:构建、运行

4、docker镜像的版本管理

5、容期间网络访问:–link

6、镜像打包历史

7、服务运行效果

以上为个人经验,希望能给大家一个参考,也希望大家多多支持www.887551.com。如有错误或未考虑完全的地方,望不吝赐教。