Apollo(阿波罗)是携程框架部门研发的分布式配置中心,在不考虑高可用和负载均衡的情况下,它最少需要四个组件才能最小化运行,分别是:
- apollo-configservice:提供配置管理服务,如果有多套环境,那么每个环境都需要部署。内置Eureka服务器。
- apollo-adminService:提供后台管理服务,如果有多套环境,那么每个环境都需要部署。
- apollo-portal:提供Web用户界面,只需要部署一个服务即可。
- apollo-db:基于MySQL,包含ApolloConfigDB和ApolloPortalDB数据库。
本文将为上述几个组件制作Docker镜像,然后通过服务编排的方式容器化部署Apollo服务,借此提高部署的灵活性,并且简化部署过程。
- CPU:双核
- 内存:4 GB
- 硬盘:120 GB
- IP:192.168.190.128
- 操作系统:CentOS 7.4-1708 x86_64 Minimal
- 版本:1.12.6
- 安装方式:参考《如何通过yum安装Docker和Docker-Compose》
- 版本:1.19.0
- 安装方式:参考《如何通过yum安装Docker和Docker-Compose》
在shell中运行以下命令,创建制作apollo-configservice镜像的专用目录:
mkdir -pv /root/Downloads/apollo-configservice-build
根据《如何编译安装Apollo服务器(单机版)》编译Apollo的源码,获得apollo-configservice-0.11.0-SNAPSHOT-github.zip
压缩包文件,然后将其放至/root/Downloads/apollo-configservice-build
目录。
在shell中运行以下命令,创建容器使用的apollo-configservice服务的启动脚本:
cd /root/Downloads/apollo-configservice-build/
cat > startup.sh << "EOF"
#! /bin/bash
# 获取容器IP地址
host_ip=$(ifconfig eth0 | grep inet | grep -v 127.0.0.1 | grep -v inet6 | awk '{print $2}' | tr -d "addr:")
# 替换启动脚本的IP地址
sed -i "19d" apollo-configservice/scripts/startup.sh
sed -i "18a\SERVER_URL=\"http:\/\/$host_ip:\$SERVER_PORT\"" apollo-configservice/scripts/startup.sh
# 启动apollo-configservice服务
/bin/bash apollo-configservice/scripts/startup.sh
EOF
apollo-configservice容器启动时,会自动运行上述脚本来启动apollo-configservice服务。
supervisor是一种Linux的进程管理工具,apollo-configservice容器会用其管理自身的后台服务。在shell中运行以下命令,创建supervisord.conf
文件:
cat > supervisord.conf << "EOF"
[supervisord]
nodaemon=true
[program:apollo-configservice]
command=/bin/bash startup.sh
EOF
在shell中运行以下命令,创建用于制作apollo-configservice镜像的Dockerfile文件:
cat > Dockerfile << "EOF"
# 使用自建的CentOS 6.9基础镜像
FROM registry.cn-hangzhou.aliyuncs.com/ghoulich-centos/centos:6.9
# 镜像维护者
MAINTAINER [email protected]
# 拷贝apollo-configservice压缩包和启动脚本
COPY apollo-configservice-0.11.0-SNAPSHOT-github.zip /
COPY startup.sh /
COPY supervisord.conf /etc/supervisord.conf
# 安装OpenJDK和unzip
RUN yum install -y epel-release
RUN yum install -y java-1.8.0-openjdk unzip supervisor
# 解压缩apollo-configservice压缩包
RUN unzip -d apollo-configservice apollo-configservice-0.11.0-SNAPSHOT-github.zip \
&& rm -rf apollo-configservice-0.11.0-SNAPSHOT-github.zip
# 设置时区
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
&& echo "Asia/Shanghai" > /etc/timezone
# 清理系统
RUN yum clean all
# 开放8080端口
EXPOSE 8080
# 创建日志目录挂载点
VOLUME ["/var/log/apollo/configservice"]
# 自启动supervisor
CMD ["/usr/bin/supervisord"]
EOF
上述文件有两点需要注意:
- 公开8080端口,这是apollo-configservice的默认服务端口。
- 创建日志目录的挂载点,这样便可以通过宿主机直接查看和跟踪容器的日志。
在shell中运行以下命令,创建apollo-configservice镜像:
docker build -t apollo-configservice:latest .
本文会将Docker镜像交给阿里云进行托管。运行以下命令,登录阿里云镜像库,然后创建镜像标签,最后推送镜像:
# 登录阿里云镜像库
docker login [email protected] registry.cn-hangzhou.aliyuncs.com
# 创建镜像标签
docker tag apollo-configservice:latest registry.cn-hangzhou.aliyuncs.com/ghoulich-centos/apollo-configservice:0.11.0
# 推送镜像
docker push registry.cn-hangzhou.aliyuncs.com/ghoulich-centos/apollo-configservice:0.11.0
上传成功之后,可以在阿里云的容器镜像服务控制台中看到apollo-configservice镜像,如下图所示:
如果要单独部署apollo-configservice容器,那么可以使用以下命令:
docker run --detach \
--name apollo-configservice \
--hostname apollo-configservice \
--env JAVA_OPTS="$JAVA_OPTS -Dapollo_profile=github -Dspring.datasource.url=jdbc:mysql://192.168.190.128:3306/ApolloConfigDB?characterEncoding=utf8 -Dspring.datasource.username=root -Dspring.datasource.password=123.Org$%^" \
--publish 8080:8080 \
--volume /var/log/apollo/configservice:/var/log/apollo/configservice \
registry.cn-hangzhou.aliyuncs.com/ghoulich-centos/apollo-configservice:0.11.0
上述命令有几个选项需要注意:
--env
:通过JAVA_OPTS环境变量,将需要的JDBC配置传入容器;--publish
:将容器的8080端口映射至宿主机的8080端口;--volume
:将宿主机的日志目录挂载至容器。
在shell中运行以下命令,创建制作apollo-adminservice镜像的专用目录:
mkdir -pv /root/Downloads/apollo-adminservice-build
根据《如何编译安装Apollo服务器(单机版)》编译Apollo的源码,获得apollo-adminservice-0.11.0-SNAPSHOT-github.zip
压缩包文件,然后将其放至/root/Downloads/apollo-adminservice-build
目录。
在shell中运行以下命令,创建容器使用的apollo-adminservice服务的启动脚本:
cd /root/Downloads/apollo-adminservice-build
cat > startup.sh << "EOF"
#! /bin/bash
# 获取容器IP地址
host_ip=$(ifconfig eth0 | grep inet | grep -v 127.0.0.1 | grep -v inet6 | awk '{print $2}' | tr -d "addr:")
# 替换启动脚本的IP地址
sed -i "19d" apollo-adminservice/scripts/startup.sh
sed -i "18a\SERVER_URL=\"http:\/\/$host_ip:\$SERVER_PORT\"" apollo-adminservice/scripts/startup.sh
# 启动apollo-adminservice服务
/bin/bash apollo-adminservice/scripts/startup.sh
EOF
apollo-adminservice容器启动时,会自动运行上述脚本来启动apollo-adminservice服务。
supervisor是一种Linux的进程管理工具,apollo-adminservice容器会用其管理自身的后台服务。在shell中运行以下命令,创建supervisord.conf
文件:
cat > supervisord.conf << "EOF"
[supervisord]
nodaemon=true
[program:apollo-adminservice]
command=/bin/bash startup.sh
EOF
在shell中运行以下命令,创建用于制作apollo-adminservice镜像的Dockerfile文件:
cat > Dockerfile << "EOF"
# 使用自建的CentOS 6.9基础镜像
FROM registry.cn-hangzhou.aliyuncs.com/ghoulich-centos/centos:6.9
# 镜像维护者
MAINTAINER [email protected]
# 拷贝apollo-adminservice压缩包和启动脚本
COPY apollo-adminservice-0.11.0-SNAPSHOT-github.zip /
COPY startup.sh /
COPY supervisord.conf /etc/supervisord.conf
# 安装OpenJDK和unzip
RUN yum install -y epel-release
RUN yum install -y java-1.8.0-openjdk unzip supervisor
# 解压缩apollo-adminservice压缩包
RUN unzip -d apollo-adminservice apollo-adminservice-0.11.0-SNAPSHOT-github.zip \
&& rm -rf apollo-adminservice-0.11.0-SNAPSHOT-github.zip
# 设置时区
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
&& echo "Asia/Shanghai" > /etc/timezone
# 清理系统
RUN yum clean all
# 开放8090端口
EXPOSE 8090
# 创建日志目录挂载点
VOLUME ["/var/log/apollo/adminservice"]
# 自启动supervisor
CMD ["/usr/bin/supervisord"]
EOF
上述文件有两点需要注意:
- 公开8090端口,这是apollo-adminservice的默认服务端口。
- 创建日志目录的挂载点,这样便可以通过宿主机直接查看和跟踪容器的日志。
在shell中运行以下命令,创建apollo-adminservice镜像:
docker build -t apollo-adminservice:latest .
本文会将Docker镜像交给阿里云进行托管。运行以下命令,登录阿里云镜像库,然后创建镜像标签,最后推送镜像:
# 登录阿里云镜像库
docker login [email protected] registry.cn-hangzhou.aliyuncs.com
# 创建镜像标签
docker tag apollo-adminservice:latest registry.cn-hangzhou.aliyuncs.com/ghoulich-centos/apollo-adminservice:0.11.0
# 推送镜像
docker push registry.cn-hangzhou.aliyuncs.com/ghoulich-centos/apollo-adminservice:0.11.0
上传成功之后,可以在阿里云的容器镜像服务控制台中看到apollo-adminservice镜像,如下图所示:
如果要单独部署apollo-adminservice容器,那么可以使用以下命令:
docker run --detach \
--name apollo-adminservice \
--hostname apollo-adminservice \
--env JAVA_OPTS="$JAVA_OPTS -Dapollo_profile=github -Dspring.datasource.url=jdbc:mysql://192.168.190.128:3306/ApolloConfigDB?characterEncoding=utf8 -Dspring.datasource.username=root -Dspring.datasource.password=123.Org$%^" \
--publish 8090:8090 \
--volume /var/log/apollo/adminservice:/var/log/apollo/adminservice \
registry.cn-hangzhou.aliyuncs.com/ghoulich-centos/apollo-adminservice:0.11.0
上述命令有几个选项需要注意:
--env
:通过JAVA_OPTS环境变量,将需要的JDBC配置传入容器;--publish
:将容器的8090端口映射至宿主机的8090端口;--volume
:将宿主机的日志目录挂载至容器。
在shell中运行以下命令,创建制作apollo-portal镜像的专用目录:
mkdir -pv /root/Downloads/apollo-portal-build
根据《如何编译安装Apollo服务器(单机版)》编译Apollo的源码,获得apollo-portal-0.11.0-SNAPSHOT-github.zip
压缩包文件,然后将其放至/root/Downloads/apollo-portal-build
目录。
在shell中运行以下命令,创建容器使用的apollo-portal服务的启动脚本:
cd /root/Downloads/apollo-portal-build
cat > startup.sh << "EOF"
#! /bin/bash
# 获取容器IP地址
host_ip=$(ifconfig eth0 | grep inet | grep -v 127.0.0.1 | grep -v inet6 | awk '{print $2}' | tr -d "addr:")
# 替换启动脚本的IP地址
sed -i "19d" apollo-portal/scripts/startup.sh
sed -i "18a\SERVER_URL=\"http:\/\/$host_ip:\$SERVER_PORT\"" apollo-portal/scripts/startup.sh
# 启动apollo-portal服务
/bin/bash apollo-portal/scripts/startup.sh
EOF
apollo-portal容器启动时,会自动运行上述脚本来启动apollo-portal服务。
supervisor是一种Linux的进程管理工具,apollo-portal容器会用其管理自身的后台服务。在shell中运行以下命令,创建supervisord.conf
文件:
cat > supervisord.conf << "EOF"
[supervisord]
nodaemon=true
[program:apollo-portal]
command=/bin/bash startup.sh
EOF
在shell中运行以下命令,创建用于制作apollo-portal镜像的Dockerfile文件:
cat > Dockerfile << "EOF"
# 使用自建的CentOS 6.9基础镜像
FROM registry.cn-hangzhou.aliyuncs.com/ghoulich-centos/centos:6.9
# 镜像维护者
MAINTAINER [email protected]
# 拷贝apollo-portal压缩包和启动脚本
COPY apollo-portal-0.11.0-SNAPSHOT-github.zip /
COPY startup.sh /
COPY supervisord.conf /etc/supervisord.conf
# 安装OpenJDK和unzip
RUN yum install -y epel-release
RUN yum install -y java-1.8.0-openjdk unzip supervisor
# 解压缩apollo-portal压缩包
RUN unzip -d apollo-portal apollo-portal-0.11.0-SNAPSHOT-github.zip \
&& rm -rf apollo-portal-0.11.0-SNAPSHOT-github.zip
# 设置时区
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
&& echo "Asia/Shanghai" > /etc/timezone
# 清理系统
RUN yum clean all
# 开放8070端口
EXPOSE 8070
# 创建日志目录挂载点
VOLUME ["/var/log/apollo/portal"]
# 自启动supervisor
CMD ["/usr/bin/supervisord"]
EOF
上述文件有两点需要注意:
- 公开8070端口,这是apollo-portal的默认服务端口。
- 创建日志目录的挂载点,这样便可以通过宿主机直接查看和跟踪容器的日志。
在shell中运行以下命令,创建apollo-portal镜像:
docker build -t apollo-portal:latest .
本文会将Docker镜像交给阿里云进行托管。运行以下命令,登录阿里云镜像库,然后创建镜像标签,最后推送镜像:
# 登录阿里云镜像库
docker login [email protected] registry.cn-hangzhou.aliyuncs.com
# 创建镜像标签
docker tag apollo-portal:latest registry.cn-hangzhou.aliyuncs.com/ghoulich-centos/apollo-portal:0.11.0
# 推送镜像
docker push registry.cn-hangzhou.aliyuncs.com/ghoulich-centos/apollo-portal:0.11.0
上传成功之后,可以在阿里云的容器镜像服务控制台中看到apollo-portal镜像,如下图所示:
如果要单独部署apollo-portal容器,那么可以使用以下命令:
docker run --detach \
--name apollo-portal \
--hostname apollo-portal \
--env JAVA_OPTS="$JAVA_OPTS -Dapollo_profile=github,auth -Ddev_meta=http://192.168.190.128:8080/ -Dserver.port=8070 -Dspring.datasource.url=jdbc:mysql://192.168.190.128:3306/ApolloPortalDB?characterEncoding=utf8 -Dspring.datasource.username=root -Dspring.datasource.password=123.Org$%^" \
--publish 8070:8070 \
--volume /var/log/apollo/portal:/var/log/apollo/portal \
registry.cn-hangzhou.aliyuncs.com/ghoulich-centos/apollo-portal:0.11.0
上述命令有几个选项需要注意:
--env
:通过JAVA_OPTS环境变量,将需要的JDBC配置和Eureka服务器地址传入容器;--publish
:将容器的8070端口映射至宿主机的8070端口;--volume
:将宿主机的日志目录挂载至容器。
在shell中运行以下命令,创建编排Apollo服务的专用目录:
mkdir -pv /root/Downloads/apollo-compose
在shell中运行以下命令,克隆Apollo的源码库,然后复制数据库初始化脚本:
cd /root/Downloads/
git clone https://github.com/ctripcorp/apollo.git
cp apollo/scripts/sql/apolloconfigdb.sql apollo-docker/apollo-compose/
cp apollo/scripts/sql/apolloportaldb.sql apollo-docker/apollo-compose/
cd /root/Downloads/apollo-compose
本文使用自建的MySQL镜像作为父镜像,制作apollo-db镜像。在shell中运行以下命令,创建my.cnf
配置文件:
cat > my.cnf << "EOF"
# For advice on how to change settings please see
# http://dev.mysql.com/doc/refman/5.7/en/server-configuration-defaults.html
[mysqld]
#
# Remove leading # and set to the amount of RAM for the most important data
# cache in MySQL. Start at 70% of total RAM for dedicated server, else 10%.
# innodb_buffer_pool_size = 128M
#
# Remove leading # to turn on a very important data integrity option: logging
# changes to the binary log between backups.
# log_bin
#
# Remove leading # to set options mainly useful for reporting servers.
# The server defaults are faster for transactions and fast SELECTs.
# Adjust sizes as needed, experiment to find the optimal values.
# join_buffer_size = 128M
# sort_buffer_size = 2M
# read_rnd_buffer_size = 2M
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0
log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid
[mysql]
default-character-set=utf8
EOF
注意,本文的数据库容器采用外置配置文件的方式,将my.cnf
文件放置在宿主机中,可以简便地修改数据库配置。
在shell中运行以下命令,创建apollo-db容器启动MySQL数据库的脚本文件:
cat > start.sh << "EOF"
#! /bin/bash
# Source function library.
. /etc/rc.d/init.d/functions
# Source networking configuration.
. /etc/sysconfig/network
exec="/usr/bin/mysqld_safe"
prog="mysqld"
# Set timeouts here so they can be overridden from /etc/sysconfig/mysqld
STARTTIMEOUT=120
# Set in /etc/sysconfig/mysqld, will be passed to mysqld_safe
MYSQLD_OPTS=
[ -e /etc/sysconfig/$prog ] && . /etc/sysconfig/$prog
lockfile=/var/lock/subsys/$prog
# Support for extra options passed to mysqld
command=$1 && shift
extra_opts="$@"
# Extract value of a MySQL option from config files
# Usage: get_mysql_option OPTION DEFAULT SECTION1 SECTION2 SECTIONN
# Result is returned in $result
# We use my_print_defaults which prints all options from multiple files,
# with the more specific ones later; hence take the last match.
get_mysql_option () {
option=$1
default=$2
shift 2
result=$(/usr/bin/my_print_defaults "$@" | sed -n "s/^--${option}=//p" | tail -n 1)
if [ -z "$result" ]; then
# not found, use default
result="${default}"
fi
}
get_mysql_option datadir "/var/lib/mysql" mysqld
datadir="$result"
get_mysql_option socket "$datadir/mysql.sock" mysqld
socketfile="$result"
get_mysql_option log-error "/var/log/mysqld.log" mysqld mysqld_safe
errlogfile="$result"
get_mysql_option pid-file "/var/run/mysqld/mysqld.pid" mysqld mysqld_safe
mypidfile="$result"
case $socketfile in
/*) adminsocket="$socketfile" ;;
*) adminsocket="$datadir/$socketfile" ;;
esac
install_validate_password_sql_file () {
local initfile
initfile="$(mktemp /var/lib/mysql-files/install-validate-password-plugin.XXXXXX.sql)"
chmod a+r "$initfile"
echo "SET @@SESSION.SQL_LOG_BIN=0;" > "$initfile"
echo "INSERT INTO mysql.plugin (name, dl) VALUES ('validate_password', 'validate_password.so');" >> "$initfile"
echo "$initfile"
}
start(){
[ -x $exec ] || exit 5
# check to see if it's already running
RESPONSE=$(/usr/bin/mysqladmin --no-defaults --socket="$adminsocket" --user=UNKNOWN_MYSQL_USER ping 2>&1)
if [ $? = 0 ]; then
# already running, do nothing
action $"Starting $prog: " /bin/true
ret=0
elif echo "$RESPONSE" | grep -q "Access denied for user"
then
# already running, do nothing
action $"Starting $prog: " /bin/true
ret=0
else
# prepare for start
if [ ! -e "$errlogfile" -a ! -h "$errlogfile" -a "x$(dirname "$errlogfile")" = "x/var/log" ]; then
install /dev/null -m0640 -omysql -gmysql "$errlogfile"
fi
[ -x /sbin/restorecon ] && /sbin/restorecon "$errlogfile"
if [ ! -d "$datadir/mysql" ] ; then
# First, make sure $datadir is there with correct permissions
if [ ! -d "$datadir" -a ! -h "$datadir" -a "x$(dirname "$datadir")" = "x/var/lib" ]; then
install -d -m0751 -omysql -gmysql "$datadir" || exit 1
fi
if [ ! -h "$datadir" -a "x$(dirname "$datadir")" = "x/var/lib" ]; then
chown mysql:mysql "$datadir"
chmod 0751 "$datadir"
fi
if [ -x /sbin/restorecon ]; then
/sbin/restorecon "$datadir"
for dir in /var/lib/mysql-files /var/lib/mysql-keyring ; do
if [ -x /usr/sbin/semanage -a -d /var/lib/mysql -a -d $dir ] ; then
/usr/sbin/semanage fcontext -a -e /var/lib/mysql $dir >/dev/null 2>&1
/sbin/restorecon -r $dir
fi
done
fi
# Now create the database
initfile="$(install_validate_password_sql_file)"
action $"Initializing MySQL database: " /usr/sbin/mysqld --initialize --datadir="$datadir" --user=mysql --init-file="$initfile"
ret=$?
rm -f "$initfile"
[ $ret -ne 0 ] && return $ret
# Generate certs if needed
if [ -x /usr/bin/mysql_ssl_rsa_setup -a ! -e "${datadir}/server-key.pem" ] ; then
/usr/bin/mysql_ssl_rsa_setup --datadir="$datadir" --uid=mysql >/dev/null 2>&1
fi
fi
if [ ! -h "$datadir" -a "x$(dirname "$datadir")" = "x/var/lib" ]; then
chown mysql:mysql "$datadir"
chmod 0751 "$datadir"
fi
# Pass all the options determined above, to ensure consistent behavior.
# In many cases mysqld_safe would arrive at the same conclusions anyway
# but we need to be sure. (An exception is that we don't force the
# log-error setting, since this script doesn't really depend on that,
# and some users might prefer to configure logging to syslog.)
# Note: set --basedir to prevent probes that might trigger SELinux
# alarms, per bug #547485
$exec $MYSQLD_OPTS --datadir="$datadir" --socket="$socketfile" \
--pid-file="$mypidfile" \
--basedir=/usr --user=mysql $extra_opts >/dev/null &
safe_pid=$!
# Spin for a maximum of N seconds waiting for the server to come up;
# exit the loop immediately if mysqld_safe process disappears.
# Rather than assuming we know a valid username, accept an "access
# denied" response as meaning the server is functioning.
ret=0
TIMEOUT="$STARTTIMEOUT"
while [ $TIMEOUT -gt 0 ]; do
RESPONSE=$(/usr/bin/mysqladmin --no-defaults --socket="$adminsocket" --user=UNKNOWN_MYSQL_USER ping 2>&1) && break
echo "$RESPONSE" | grep -q "Access denied for user" && break
if ! /bin/kill -0 $safe_pid 2>/dev/null; then
echo "MySQL Daemon failed to start."
ret=1
break
fi
sleep 1
let TIMEOUT=${TIMEOUT}-1
done
if [ $TIMEOUT -eq 0 ]; then
echo "Timeout error occurred trying to start MySQL Daemon."
ret=1
fi
if [ $ret -eq 0 ]; then
action $"Starting $prog: " /bin/true
touch $lockfile
else
action $"Starting $prog: " /bin/false
fi
fi
return $ret
}
# 启动MySQL服务
start
# 修改初始密码
init_passwd=$(sed -rn 's/^(.*)(root@localhost: )(.*)$/\3/p' /var/log/mysqld.log)
mysql --user=root --password=${init_passwd} --connect-expired-password --execute="ALTER USER 'root'@'localhost' IDENTIFIED BY '123.Org$%^';"
mysql --user=root --password=123.Org$%^ --execute="GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY '123.Org$%^' WITH GRANT OPTION;"
mysql --user=root --password=123.Org$%^ --execute="FLUSH PRIVILEGES;"
# 初始化Apollo数据库
mysql --user=root --password=123.Org$%^ < apolloportaldb.sql
mysql --user=root --password=123.Org$%^ < apolloconfigdb.sql
# 配置Eureka地址
mysql --user=root --password=123.Org$%^ --execute="UPDATE ApolloConfigDB.ServerConfig SET Value='http://${HOST_IP}:8080/eureka/' WHERE Id=1;"
EOF
注意,上述启动脚本改编自MySQL的服务启动脚本。当apollo-db容器启动时,首先会启动MySQL服务,然后将root用户的初始密码修改为123.Org$%^
,然后初始化ApolloPortalDB和ApolloConfigDB数据库,最后将真实的Eureka服务器地址存入数据库。
在shell中运行以下命令,创建apollo-db镜像的Dockerfile文件:
cat > Dockerfile << "EOF"
FROM registry.cn-hangzhou.aliyuncs.com/ghoulich-centos/centos-6.9-mysql:5.7.21
MAINTAINER [email protected]
COPY apolloconfigdb.sql /apolloconfigdb.sql
COPY apolloportaldb.sql /apolloportaldb.sql
COPY start.sh /start.sh
EOF
在进行服务编排时才会构建apollo-db镜像,不需要人为手动构建,也不会将apollo-db镜像上传至阿里云。
在shell中运行以下命令,创建docker-compose.yml
服务编排配置文件:
cat > docker-compose.yml << "EOF"
version: '2'
services:
apollo-db:
build:
context: ./
dockerfile: Dockerfile
image: apollo-db:latest
container_name: apollo-db
hostname: apollo-db
environment:
TZ: Asia/Shanghai
ports:
- "3306:3306"
volumes:
- /usr/local/mysql/log/mysqld.log:/var/log/mysqld.log
- /usr/local/mysql/config/my.cnf:/etc/my.cnf
- /usr/local/mysql/data:/var/lib/mysql
networks:
apollo_network:
ipv4_address: 172.16.238.101
apollo-configservice:
image: registry.cn-hangzhou.aliyuncs.com/ghoulich-centos/apollo-configservice:0.11.0
container_name: apollo-configservice
hostname: apollo-configservice
environment:
JAVA_OPTS: "-Dapollo_profile=github -Dspring.datasource.url=jdbc:mysql://172.16.238.101:3306/ApolloConfigDB?characterEncoding=utf8 -Dspring.datasource.username=root -Dspring.datasource.password=123.Org$$%^"
depends_on:
- apollo-db
ports:
- "8080:8080"
volumes:
- /var/log/apollo/configservice:/var/log/apollo/configservice
networks:
apollo_network:
ipv4_address: 172.16.238.102
apollo-adminservice:
image: registry.cn-hangzhou.aliyuncs.com/ghoulich-centos/apollo-adminservice:0.11.0
container_name: apollo-adminservice
hostname: apollo-adminservice
environment:
JAVA_OPTS: "-Dapollo_profile=github -Dspring.datasource.url=jdbc:mysql://172.16.238.101:3306/ApolloConfigDB?characterEncoding=utf8 -Dspring.datasource.username=root -Dspring.datasource.password=123.Org$$%^"
depends_on:
- apollo-configservice
ports:
- "8090:8090"
volumes:
- /var/log/apollo/adminservice:/var/log/apollo/adminservice
networks:
apollo_network:
ipv4_address: 172.16.238.103
apollo-protal:
image: registry.cn-hangzhou.aliyuncs.com/ghoulich-centos/apollo-portal:0.11.0
container_name: apollo-portal
hostname: apollo-portal
environment:
JAVA_OPTS: "-Dapollo_profile=github,auth -Ddev_meta=http://172.16.238.102:8080/ -Dserver.port=8070 -Dspring.datasource.url=jdbc:mysql://172.16.238.101:3306/ApolloPortalDB?characterEncoding=utf8 -Dspring.datasource.username=root -Dspring.datasource.password=123.Org$$%^"
depends_on:
- apollo-adminservice
ports:
- "8070:8070"
volumes:
- /var/log/apollo/portal:/var/log/apollo/portal
networks:
apollo_network:
ipv4_address: 172.16.238.104
networks:
apollo_network:
driver: bridge
ipam:
driver: default
config:
- subnet: 172.16.238.0/24
gateway: 172.16.238.1
EOF
注意,docker-compose.yml
文件定义了四个服务,分别如下所示:
这个服务的关键配置,如下所示:
-
build 在部署服务时构建apollo-db镜像,根据当前目录的Dockerfile文件进行构建。
-
image 构建镜像的名称为apollo-db,标签为latest。
-
ports 将容器的3306端口映射至宿主机的3306端口。
-
volumes 将容器的日志、配置和数据目录挂载至宿主机。
-
networks 加入名为apollo_network的网络,分配的静态IP地址为172.16.238.101。
这个服务的关键配置,如下所示:
-
environment 通过JAVA_OPTS环境变量,将需要的JDBC配置传入容器。
-
depends_on 依赖于apollo-db容器。
-
ports 将容器的8080端口映射至宿主机的8080端口。
-
volumes 将容器的日志目录挂载至宿主机。
-
networks 加入名为apollo_network的网络,分配的静态IP地址为172.16.238.102。
这个服务的关键配置,如下所示:
-
environment 通过JAVA_OPTS环境变量,将需要的JDBC配置传入容器。
-
depends_on 依赖于apollo-configservice容器。
-
ports 将容器的8090端口映射至宿主机的8090端口。
-
volumes 将容器的日志目录挂载至宿主机。
-
networks 加入名为apollo_network的网络,分配的静态IP地址为172.16.238.103。
这个服务的关键配置,如下所示:
-
environment 通过JAVA_OPTS环境变量,将需要的JDBC配置和Eureka服务器地址传入容器。
-
depends_on 依赖于apollo-adminservice容器。
-
ports 将容器的8070端口映射至宿主机的8070端口。
-
volumes 将容器的日志目录挂载至宿主机。
-
networks 加入名为apollo_network的网络,分配的静态IP地址为172.16.238.104。
注意,docker-compose.yml
文件还定义了一个名为apollo_network的网络。这个网络的关键配置,如下所示:
-
driver 使用桥接(bridge)网络。
-
subnet 设置子网为172.16.238.0/24。
-
gateway 子网的网关为172.16.238.1。
在shell中运行以下命令,创建Apollo服务启动脚本:
cat > start-apollo.sh << "EOF"
#! /bin/bash
# 创建必要的目录和文件
mkdir -p /usr/local/mysql/{data,log,config}
touch /usr/local/mysql/log/mysqld.log
cp my.cnf /usr/local/mysql/config/
chown -R 27:27 /usr/local/mysql
# 获取本机IP地址
host_ip=$(ifconfig ens33 | grep inet | grep -v 127.0.0.1 | grep -v inet6 | awk '{print $2}' | tr -d "addr:")
# 向docker-compose.yml添加主机IP地址
sed -i "12a\ HOST_IP: ${host_ip}" docker-compose.yml
# 启动Apollo容器集群
docker-compose up -d
EOF
这个脚本可以实现一键编排和部署容器化的Apollo服务。注意,第11行获取宿主机IP地址时,本文使用的网卡名为ens33,应该指定实际的网卡名称。
在shell中运行以下命令,创建Apollo服务停止脚本:
cat > shutdown-apollo.sh << "EOF"
#! /bin/bash
# 停止Apollo容器集群
docker-compose down
# 删除apollo-db镜像
docker rmi apollo-db
# 删除数据库相关目录
rm -rf /usr/local/mysql
EOF
注意,上述脚本会停止Apollo容器集群,然后删除本地的apollo-db镜像,最后删除Apollo服务的所有数据,使得宿主机恢复初始状态!
将本文涉及的所有文件都上传至GitHub或自建的GitLab,目录结构如下图所示:
在shell中运行以下命令,从GitHub克隆Apollo服务配置文件:
cd /root/Downloads
git clone https://github.com/ghoulich/apollo-docker.git
在shell中运行以下命令,启动Apollo容器集群:
cd /root/Downloads/apollo-docker/apollo-compose
/bin/bash start-apollo.sh
请持续跟踪/var/log/apollo
目录,查看有没有预料之外的异常。注意,服务启动时,发生Eureka连接异常是正常现象,只要不是持续不断地出现,就不必理会!
如果要停止Apollo服务,将宿主机恢复成初始状态,请运行以下命令:
cd apollo-docker/apollo-compose
/bin/bash shutdown-apollo.sh
在shell中运行以下命令,检查Apollo容器集群的运行状态
docker ps
若上述命令的输出信息如下图所示,则表示Apollo各个服务组件的容器正在运行:
在shell中运行以下命令,调用apollo-configservice服务的health接口:
curl http://192.168.190.128:8080/health
若上述命令的输出信息如下图所示,则表示apollo-configservice服务运行正常:
在shell中运行以下命令,调用apollo-adminservice服务的health接口:
curl http://192.168.190.128:8090/health
若上述命令的输出信息如下图所示,则表示apollo-adminservice服务运行正常:
在shell中运行以下命令,调用apollo-portal服务的health接口:
curl http://192.168.190.128:8070/health
若上述命令的输出信息如下图所示,则表示apollo-portal服务运行正常:
在Web浏览器中访问Eureka管理页面,URL如下所示:
http://192.168.190.128:8080/
若能够看到如下图的信息,则表示apollo-configservice和apollo-adminservice服务注册成功:
在Web浏览器中访问Apollo Portal系统,URL如下所示:
http://192.168.190.128:8070/signin
填写默认的用户名/密码,分别是apollo/admin。登录成功后便进入控制台首页,如下图所示:
至此,编排和部署容器化的Apollo服务已经全部完成了。接下来,还需要编写apollo-demo示例工程,整理Apollo的使用方法!