Docker 生产环境容器化

修改存储目录

生产环境中,镜像多了之后很容易把硬盘写满造成服务器宕机,所以需要挂载一块较大的硬盘,修改 docker 的默认存储路径,下面提供两种方案。

方案一:软连接

1
2
3
service docker stop
mv /var/lib/docker /mnt/sdc/docker
ln -s /mnt/sdc/docker /var/lib/docker

方案二:修改配置

配置 deamon 启动时 -g 参数,可以直接改变存储路径。

Ubuntu 系统需要先修改 /lib/systemd/system/docker.service 文件:

1
2
3
4
5
6
...
[Service]
ExecStart=/usr/bin/docker -d $DOCKER_OPTS
...
EnvironmentFile=-/etc/default/docker
...

其中 ExecStart 就是 deamon 的启动命令,可以直接在后面加参数,也可以选择上述 EnvironmentFile 配置 ,然后将启动参数写到 /etc/default/docker 文件中:

1
DOCKER_OPTS="-g /mnt/sdc/docker"

配置好之后,执行下面命令重新加载配置文件:

1
2
systemctl daemon-reload
systemctl restart docker

参考:How do I change the Docker image installation directory?

Insecure Registry

生产环境中部署 docker,需要在搭建一个私有 registry:

1
docker run -d -p 5000:5000 --restart=always --name registry registry:2

启动之后,没法直接进行镜像的 push/pull,因为默认要求配置 TLS。

为了图方便,可以暂时把私有的 registry 加入为 insecure-registry 进行测试。

insecure-registry 也是通过添加 deamon 的启动参数实现的,可在 /etc/default/docker 中配置:

1
DOCKER_OPTS="--insecure-registry 192.168.1.19:5000"

然后重启即可。

参考:Deploying a plain HTTP registry

集群方案

docker 集群部署目前有两种方案,一般称作 一代 swarm二代 swarm

一代 swarm

官方文档

一代 swarm 是以容器的方式进行集群管理的,需要在每个节点上运行一个 swarm 容器,便可进行集群管理。

需要注意的是,一代 swarm 还需要自己手动运行 k/v 服务容器,参考,运行起来之后可能会遇到报错:

1
Error response from daemon: datastore for scope "global" is not initialized

这其实是 deamon 没有配置 cluster-advertisecluster-store 所致,需要在/etc/default/docker 中配置这两项,具体可参考 Nodes discovery

二代 swarm

官方文档

二代 swarm 直接将 swarm 模式集成在 docker 里面,只需要简单的配置即可,参考:Create a swarm

界面方案

ui-for-docker 作为管理的 web 界面,但是过于简陋,后来有找到一个基于 ui-for-docker 实现的 portainer,支持 swarm mode,使用起来非常方便,也可以根据自己的需求修改。

集群实践

实践过程中我分别尝试了一代 swarm 和二代 swarm。

版本 配置过程 管理 扩容
一代 1. 配置 k/v store。2. 宿主机 docker deamon 监听某个端口。 3.在每台宿主机上运行 swarm 容器。 在任何一个节点都可以进行集群的管理 手动扩容
二代 1. manager init swarm mode 2. worker join 只能在 manager 节点进行管理 自动扩容

简单的说就是一个 nginx 的环境,以下是具体步骤:

  1. 使用二代 swarm。
  2. 创建一个 overlay 网络。
  3. 创建 nginx 服务。

需要明确的几点:

  1. 二代 swarm 在同一个网络下服务可以通过服务名发现其他服务。
  2. 二代 swarm 部署之后,将会监听每个节点上 publish 的端口,收到的请求会负载均衡到所有的 tasks 中。

nginx

nginx 服务只需选择官方提供的镜像,建议使用最轻量的 nginx:alpine 版本,自定义配置文件覆盖原生的即可。

更改时区

1
2
3
4
RUN apk update && apk add ca-certificates && \
apk add tzdata && \
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
echo "Asia/Shanghai" > /etc/timezone

DNS 服务

docker 容器的 /etc/hosts 文件默认是不允许修改的,所以要自定义域名的解析就需要配置自己的内网 DNS 服务,推荐使用 dnsmsq, 然后将 deamon 的启动参数修改为 --dns=192.168.x.x 自己的 DNS 服务器,就可以实现自定义域名解析的需求。

上述修改可解决服务器被墙导致谷歌、Facebook 等三方API无法使用的问题,也可以加速服务器访问外网。

代码更新

作为 web 应用,代码需要时常上线更新,又需要在集群中部署,如果使用目录挂载的办法将带来额外的工作量,所以选择把代码直接打包到容器中,每次上线重新构建镜像,具体步骤:

  1. 代码 push 到 gitlab,触发 CI 或者 webhook,构建镜像。
  2. 镜像 push 到私有的 registry 仓库中。
  3. 二代 swarm 提供 rolling update 的机制,执行相关命令即可。

一些经验

  1. Docker 是进程容器,理论上一个容器只跑一个进程,杜绝当虚拟机使用。
  2. 要使用和宿主机一个体系的基础镜像。
  3. 国内使用建议搜索下 daocloud 镜像加速,会提升幸福感。
  4. DNS 服务器会默认使用 8.8.8.8,所以正式环境一定要配置 DNS 服务器,否则一些三方登录的接口将会变得异常缓慢。
  5. Docker 里面包含了很多新的思路,如果总是用老套路去思考,很可能就走入死胡同。
  6. 不要用百度搜索中文资料,一定要看最新的英文资料。
  7. 为了安全,确保 deamon 只监听 /var/run/docker.sock