- A+
一、实践背景
为了学习Docker,我们先结合实际需求,设计这样一个场景case:假设有一个个人网站,想使用Nginx反向代理方案,能够在国内外快速搭建多个类似于CDN的节点,提供集群式的WEB访问服务。
我想到的方案如下:
- 常规部署方案: 购买云主机->环境初始化->部署Nginx->配置反向代理->DNS解析
- Docker部署方案:购买云主机->yum 安装docker->拉取自定义镜像并执行->DNS解析
- 腾讯云容器方案: 腾讯云容器服务->创建服务->DNS解析
很明显,使用Docker部署方案,整个过程会变得简单快捷,也更易自动化。当然,若不是对IDC有特殊要求的话,腾讯云的容器服务当选为最佳方案。
下面简单记录下我从Docker镜像的创建、上传到部署的实践过程。
实验环境:
- 腾讯云:CentOS Linux release 7.2.1511 (Core)
- 阿里云:CentOS Linux release 7.2.1511 (Core)
- Docker version 1.12.6, build 88a4867/1.12.6
- Docker 镜像版本:Centos 官方最新版
- Nginx 版本:Tengine 2.2.0
- 其他略..
二、制作镜像
1、安装配置Docker
# 安装docker yum install -y docker # 配置腾讯云镜像加速(官方的龟速) vim /etc/sysconfig/docker #新增如下参数: OPTIONS='--registry-mirror=https://mirror.ccs.tencentyun.com' #重启docker服务: systemctl restart docker
2、制作基础镜像
拉取 centos官方基础镜像 docker pull centos 查看当前镜像 docker images
[root@MyServer docker]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE docker.io/centos latest 328edcd84f1b 4 weeks ago 192.5 MB
运行并进入镜像:
docker run -ti docker.io/centos:latest /bin/bash
此时,终端已经进入了镜像里面,现在我们可以根据自己的需求安装额外的组件,比如我这次需要用到crontab任务计划服务、进程守护supervisor等,那么直接在这个终端开始操作:
[root@0d7f7b8769d9 /]# yum install -y epel-release crontabs [root@0d7f7b8769d9 /]# yum install -y python-pip [root@0d7f7b8769d9 /]# pip install --upgrade pip [root@0d7f7b8769d9 /]# pip install supervisor
Ps:上面的PS提示符中的 0d7f7b8769d9 就是本次启动的 CONTAINER ID ,在下面的commit即将用到。
完成必要组件安装之后,按下 Ctrl +D 退出系统,接着使用 docker commit 命令创建新镜像,比如命名为 nginx-proxy-base,版本latest:
docker commit 0d7f7b8769d9 centos/nginx-proxy-base:latest
执行完成后,可以使用 docker images 查看刚创建的镜像:
[root@MyServer ~]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE centos/nginx-proxy-base latest 676fcfff6d3c About an hour ago 366 MB
到此,我们就创建了一个自定义的Docker基础镜像(Ps:基础镜像类似一个VM虚拟机的快照,方便后续步骤都可以从这个基础上重新制作。)
3、制作服务镜像
有了前面的基础镜像之后,我们可以在此基础之上添加应用程序或自定义配置,打包为服务镜像。以本文背景需求为例,为了方便后续维护,Nginx我采用纯静态编译方式,制作成绿色便携版本。
因此,我们先在宿主机上静态编译一个符合需求的Nginx(仅展示关键步骤,依赖组件自行搞定):
# 把所有依赖都静态编译进去 ./configure --prefix=/usr/local/nginx \ --with-http_v2_module \ --with-http_ssl_module \ --with-http_gzip_static_module \ --with-http_realip_module \ --with-pcre=../pcre-8.39 \ --with-zlib=../zlib-1.2.11 \ --with-http_sub_module \ --with-openssl=../openssl-1.0.2j \ --add-module=../ngx_cache_purge-2.3 \ --add-module=../ngx_http_substitutions_filter_module # 安装 make && make install
安装后得到 /usr/local/nginx 目录,接着我们按照实验需求修改Nginx各项配置,比如反向代理:
server { listen 80; server_name demo.domain.com; access_log /data/wwwlogs/demo.domain.com.log; index index.html index.htm index.php; location / { proxy_pass http://xxx.xxx.xxx.xxx; proxy_set_header X-Forwarded-For $remote_addr; proxy_redirect off; proxy_set_header Host demo.domain.com; } }
全部配置OK后,运行nginx,确保可以正常工作。
4、编写Dockerfile
①、创建一个目录,比如:
mkdir -p /data/docker-nginx-proxy cd /data/docker-nginx-proxy
②、创建 supervisor配置文件,注意必须非daemon模式,所以此处crond会带上-n参数:
[supervisord] nodaemon=true [program:crond] command=crond -n [program:nginx] command=/usr/local/nginx/sbin/nginx
③、继续创建其他所需文件,比如 crontab.list:
0 3 * * * /usr/local/nginx/sbin/nginx -s reload > /dev/null 2>&1
④、将前面的nginx目录拷贝过来:
cp -rf /usr/local/nginx
⑤、编写Dockerfile文件:
vim Dockerfile
FROM centos/nginx-proxy-base:latest MAINTAINER <ge@zhangge.net> # 将所需文件复制到镜像指定路径 ADD nginx /usr/local/nginx ADD supervisord.conf /etc/supervisord.conf # 定义一些命令(因为Docker是分层的,这里建议将多个命令通过&&连接,写到一个RUN里面来减少Docker层数) # 指定时区,解决Dcoker时间和宿主机时间差异问题 RUN ln -snf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \ echo Asia/Shanghai > /etc/timezone && \ ln -sf /usr/local/nginx/sbin/nginx /bin/ && \ echo 'daemon off;' >> /usr/local/nginx/conf/nginx.conf && \ crontab /etc/crontab.list # 运行 supervisor,这里注意CMD只能用一次 CMD ["/usr/bin/supervisord"]
附:dockerfile 常用指令,可以按实际需求自行添加:
FROM:指定基础image MAINTAINER:用来指定镜像创建者信息 ADD:从src复制文件到container的dest路径 RUN:在容器里面执行命令 CMD:设置container启动时执行的操作,只能是一条,多条则只执行最后一条 EXPOSE:指定容器需要映射到宿主机器的端口,也可以再run的时候指定 ENV:用于设置环境变量 VOLUME:指定挂载点,使容器中的一个目录具有持久化存储数据的功能
5、构建镜像
命令为:docker build -t="[name]:[tag]" ./ ,比如:
docker build -t="centos/nginx-proxy:v1" ./
Build完成后,再执行docker images就可以看到刚刚创建的镜像:
[root@MyServer docker-nginx-proxy]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE centos/nginx-proxy v1 f2ed91429b31 31 seconds ago 370.8 MB centos/nginx-proxy-base latest 676fcfff6d3c About an hour ago 366 MB
接着,可以下测试镜像是否能正常运行,命令语法大致如下:
docker run -v [宿主目录]:[镜像目录] -ti -p [宿主端口]:[镜像端口] 镜像名称:版本
若加上 -d 参数,docker将会后台运行,这里我们想看下刚刚创建的镜像是否正常, 所以采用前台运行模式,命令如下:
docker run -v /data/docker:/data/wwwlogs -ti -p 80:80 centos/nginx-proxy:v1
执行过程:
[root@MyServer docker-nginx-proxy ~]# docker run -v /data/docker:/data/wwwlogs -ti -p 443:443 -p 80:80 ccr.ccs.tencentyun.com/myspace/nginx-proxy:latest /usr/lib/python2.7/site-packages/supervisor/options.py:298: UserWarning: Supervisord is running as root and it is searching for its configuration file in default locations (including its current working directory); you probably want to specify a "-c" argument specifying an absolute path to a configuration file for improved security. 'Supervisord is running as root and it is searching ' 2017-09-03 06:34:59,613 CRIT Supervisor running as root (no user in config file) 2017-09-03 06:34:59,615 INFO supervisord started with pid 1 2017-09-03 06:35:00,617 INFO spawned: 'nginx' with pid 7 2017-09-03 06:35:00,622 INFO spawned: 'crond' with pid 8 2017-09-03 06:35:01,689 INFO success: nginx entered RUNNING state, process has stayed up for > than 1 seconds (startsecs) 2017-09-03 06:35:01,689 INFO success: crond entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
可以看到,镜像能够正常运行,接着我们还可以继续测试下启动的Nginx是否能够正常提供服务,这里就不详细介绍了。
三、私有仓库
前文已经制作了一个带有Nginx反向代理服务的Docker镜像,此时还只能在本地使用,若是要让其他服务器也能用到这个镜像,我们可以使用 docker registry 创建一个私有仓库,步骤如下:
1、拉取私有仓库registry
docker pull registry
此时,执行docker images应该可以看到4个镜像:
[root@MyServer docker-nginx-proxy]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE centos/nginx-proxy v1 f2ed91429b31 About an hour ago 370.8 MB centos/nginx-proxy-base latest 676fcfff6d3c 2 hours ago 366 MB docker.io/centos latest 328edcd84f1b 4 weeks ago 192.5 MB docker.io/registry latest 9d0c4eabab4d 3 months ago 33.17 MB
2、拉起仓库
docker run -d -p 5000:5000 -v /data/images:/tmp/registry docker.io/registry
3、推送镜像
第一步查看镜像列表时,拿到需要推送的镜像的ID,比如 f2ed91429b31
①、先打tag,语法如下:
docker tag [image id] [仓库地址]/[命名空间]/[镜像名称]:[版本]
②、然后push,语法如下:
docker push [仓库地址]/[命名空间]/[镜像名称]
执行过程如下所示:
[root@MyServer docker-nginx-proxy]# docker tag f2ed91429b31 localhost:5000/centos/nginx-proxy:latest [root@MyServer docker-nginx-proxy]# docker push localhost:5000/centos/nginx-proxy The push refers to a repository [localhost:5000/centos/nginx-proxy] 158fae47d4e2: Pushed 4a5dcec3edb7: Pushed ae9a40cbe568: Pushed 7abc8eb8fc0f: Pushed d8a5f0f5adc1: Pushed 7dc25a4e14aa: Pushed c7ee46ed4410: Pushing [===> ] 9.669 MB/153.1 MB b362758f4793: Pushing [======> ] 26.78 MB/192.5 MB
完成后,执行docker images就可以看到刚刚提交的镜像了:
[root@MyServer docker-nginx-proxy]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE localhost:5000/centos/nginx-proxy latest f2ed91429b31 About an hour ago 370.8 MB centos/nginx-proxy v1 f2ed91429b31 About an hour ago 370.8 MB centos/nginx-proxy-base latest 676fcfff6d3c 2 hours ago 366 MB docker.io/centos latest 328edcd84f1b 4 weeks ago 192.5 MB docker.io/registry latest 9d0c4eabab4d 3 months ago 33.17 MB
③、测试拉取:
现在可以在本机(本机可以先删除在拉取)或另找一台服务器进行docker pull拉取测试。
比如,先在宿主机上删除这个镜像:
[root@MyServer docker-nginx-proxy]# docker rmi localhost:5000/centos/nginx-proxy Untagged: localhost:5000/centos/nginx-proxy:latest Untagged: localhost:5000/centos/nginx-proxy@sha256:20e7898413c368ee8dbfac0649fbfbb2d43510c3024d01e6ea3ec3f1a5d7c152
此时,docker images 列表已经消失,再执行 docker pull 就又回来了。
[root@MyServer docker-nginx-proxy]# docker pull localhost:5000/centos/nginx-proxy Using default tag: latest Trying to pull repository localhost:5000/centos/nginx-proxy ... sha256:20e7898413c368ee8dbfac0649fbfbb2d43510c3024d01e6ea3ec3f1a5d7c152: Pulling from localhost:5000/centos/nginx-proxy Digest: sha256:20e7898413c368ee8dbfac0649fbfbb2d43510c3024d01e6ea3ec3f1a5d7c152 Status: Downloaded newer image for localhost:5000/centos/nginx-proxy:latest
4、离线方案
当私有仓库无法使用时(比如存在网络限制),我们还可以将镜像保存为一个tar包,方便离线使用,使用也非常简单:
①、export / import 方案
使用 docker ps -a 查看当前正在运行的docker镜像列表,得到对应的 CONTAINER ID,执行如下语句可以将运行中的镜像导出到指定tar包:
docker export [CONTAINER ID] > centos-nginx-proxy-latest.tar
有了tar包之后,就可以使用 import 来导入:
cat centos-nginx-proxy-latest.tar | docker import - centos/nginx-proxy:v1
②、save / load 方案
使用 docker images 查看本地已有镜像列表,得到对应的IMAGE ID,然后执行如下语句可以将本地已存在镜像保存到指定tar包:
docker save [IMAGE ID] > centos-nginx-proxy-latest.tar
后面则可以使用 load 来加载tar包镜像:
docker load < centos-nginx-proxy-latest.tar
两种方案的区别:
- export 只能导出正在运行的镜像,而 save 可以直接导出本地镜像;
- export 导出的镜像文件一般会小于 save 保存的镜像(本文实践数据:相差38MB);
- export 导出(import导入)是根据容器拿到的镜像,再导入时会丢失镜像所有的历史,所以无法进行回滚操作(docker tag <LAYER ID> <IMAGE NAME>,而save保存(load加载)的镜像,没有丢失镜像的历史,可以回滚到之前的层(layer)。
四、小结
本文记录了一个实际的Dokcer应用场景从创建、上传直到部署的详细过程,Docker为我们提供了一个新的软件发布方式,只要将应用以及相关的依赖打包成Docker镜像,并上传到镜像仓库之后,我们就可以快速拉起一个定制服务,毫无拖泥带水,从而极大的简化了部署。
- 安卓客户端下载
- 微信扫一扫
- 微信公众号
- 微信公众号扫一扫