最近花了将近一个月的时间研究了 Docker 在生产环境中的使用,做为新手,期间走了无数的弯路,这里纪录一下,但愿给别人带来微小的帮助。php
前面几部分,介绍了在搭建集群以前须要作的一些工做,后面 <集群实践> 一块结合实际应用,介绍如何架构 docker 集群。html
生产环境中,镜像多了以后很容易把硬盘写满形成服务器宕机,因此须要挂载一块较大的硬盘,修改 docker 的默认存储路径,下面提供两种方案。node
方案一:软链接nginx
service docker stop mv /var/lib/docker /mnt/sdc/docker ln -s /mnt/sdc/docker /var/lib/docker
方案二:修改配置git
配置 deamon 启动时 -g
参数,能够直接改变存储路径。github
Ubuntu 系统须要先修改 /lib/systemd/system/docker.service
文件:web
... [Service] ExecStart=/usr/bin/docker -d $DOCKER_OPTS ... EnvironmentFile=-/etc/default/docker ...
其中 ExecStart
就是 deamon 的启动命令,能够直接在后面加参数,也能够选择上述 EnvironmentFile
配置 ,而后将启动参数写到 /etc/default/docker
文件中:docker
DOCKER_OPTS="-g /mnt/sdc/docker"
配置好以后,执行下面命令从新加载配置文件:ubuntu
systemctl daemon-reload systemctl restart docker
参考:How do I change the Docker image installation directory?segmentfault
生产环境中部署 docker,须要在搭建一个私有 registry:
docker run -d -p 5000:5000 --restart=always --name registry registry:2
启动以后,无法直接进行镜像的 push/pull,由于默认要求配置 TLS。
为了图方便,能够暂时把私有的 registry 加入为 insecure-registry
进行测试。
insecure-registry
也是经过添加 deamon 的启动参数实现的,可在 /etc/default/docker
中配置:
DOCKER_OPTS="--insecure-registry 192.168.1.19:5000"
而后重启便可。
参考:Deploying a plain HTTP registry
docker 集群部署目前有两种方案,通常称做 一代 swarm
和 二代 swarm
。
官方文档。
一代 swarm 是以容器的方式进行集群管理的,须要在每一个节点上运行一个 swarm 容器,即可进行集群管理,简单部署测试可参考: 在ubuntu上使用swarm搭建docker集群。
须要注意的是,一代 swarm 还须要本身手动运行 k/v 服务容器,参考,运行起来以后可能会遇到报错:
Error response from daemon: datastore for scope "global" is not initialized
这实际上是 deamon 没有配置 cluster-advertise
和 cluster-store
所致,须要在/etc/default/docker
中配置这两项,具体可参考 Nodes discovery。
官方文档。
二代 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 节点进行管理 | 自动扩容 |
目前实现了把 Segmentfault 的 web 服务迁移到容器中,简单的说就是一个 nginx + php 的环境,如下是具体步骤:
使用二代 swarm。
建立一个 overlay 网络。
建立 nginx 服务。
建立 php 及 web 代码服务。
须要明确的几点:
二代 swarm 在同一个网络下服务能够经过服务名发现其余服务。
二代 swarm 部署以后,将会监听每一个节点上 publish 的端口,收到的请求会负载均衡到全部的 tasks 中。
nginx 服务只需选择官方提供的镜像,建议使用最轻量的 nginx:alpine
版本,自定义配置文件覆盖原生的便可。
镜像直接基于官方发布的php版本版本建立。
注意: ubuntu 宿主机尽可能使用 Debian
版本的基础镜像,其余的可能会遇到各类坑。
我在开始为了追求镜像尽可能小,使用了基于 alpine
的基础镜像,遇到了如下问题:
7.1.0RC5-fpm-alpine
版本,使用 session_set_save_handler 修改 session 的 save header 为 memached 以后无法写入 session,换成了 7.0.12-alpine
就行了。
web 代码对 mount 到容器中的 www-data
用户所属的目录没有写入权限,是由于 alpine
系统中默认 www-data
的 uid
是 82, 而宿主机 Ubuntu/Debian
的是 33,在 alpine
中 uid
是 33 的用户是 xfs
,因此 mount 以后容器内部看到的文件所属用户是 xfs
,而 php-fpm 的执行用户是 www-data
, 因此才没法写入。
解决办法就是弃用 alpine
,使用基于 Debian
的基础镜像,这样带来的代价就是镜像大小翻了 10 倍。
RUN apk update && apk add ca-certificates && \ apk add tzdata && \ ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \ echo "Asia/Shanghai" > /etc/timezone
还有 php.ini 的时区配置。
docker 容器的 /etc/hosts
文件默认是不容许修改的,因此要自定义域名的解析就须要配置本身的内网 DNS 服务,推荐使用 dnsmsq
, 而后将 deamon 的启动参数修改成 --dns=192.168.x.x
本身的 DNS 服务器,就能够实现自定义域名解析的需求。
上述修改可解决服务器被墙致使谷歌、Facebook 等三方API没法使用的问题,也能够加速服务器访问外网。
做为 web 应用,代码须要时常上线更新,又须要在集群中部署,若是使用目录挂载的办法将带来额外的工做量,因此选择把代码直接打包到 php 容器中,每次上线从新构建镜像,具体步骤:
代码 push 到 gitlab,触发 CI 或者 webhook,构建镜像。
镜像 push 到私有的 registry 仓库中。
二代 swarm 提供 rolling update 的机制,执行相关命令便可。
Docker 是进程容器,理论上一个容器只跑一个进程,杜绝当虚拟机使用。
要使用和宿主机一个体系的基础镜像。
国内使用建议搜索下 daocloud 镜像加速,会提高幸福感。
DNS 服务器会默认使用 8.8.8.8
,因此正式环境必定要配置 DNS 服务器,不然一些三方登陆的接口将会变得异常缓慢。
Docker 里面包含了不少新的思路,若是老是用老套路去思考,极可能就走入死胡同。
不要用百度搜索中文资料,必定要看最新的英文资料。
为了安全,确保 deamon 只监听 /var/run/docker.sock
。
感谢能容忍我无数次搞挂生产环境的老板。
感谢每次走入死胡同后一句话点醒个人同事。
感谢群里每一位帮助个人朋友。
感谢本身的坚持。