译者按:在本专栏的前面的文章中,咱们已经提到过使用 Docker 的基本方法,所以本次讲解一下 使用 SSH 和 shell 脚本进行 Docker 镜像的自动化部署,原文仅供参考,由于对于 Docker 镜像,咱们能够有更好的解决方案:Docker Registry Hub。可是,本文仍然能够做为 shell 脚本的参考范例。程序员
当咱们将本站转移到 Docker 容器内以后,我一直在寻求能进行自动化构建和部署镜像的方法。毫无疑问,Docker 自己是一个很是完美的应用容器,可是 Docker 并无提供可以自动化更新镜像的标准方法。固然,我写了一些 shell 脚本,实现了 Docker 容器镜像的自动化部署。web
咱们假设基础架构是一台 Linux 宿主机和几个独立的 Docker 镜像,没有网站运行时产生的动态文件,例如用户上传的文件。
固然,要解决这些动态文件也很是简单,本篇文章中的脚本只须要修改一小部分,而后加上 data only container 即可以完美解决动态文件的问题。docker
那么,咱们开始进行自动化部署吧。shell
脚本的初衷很是简单:构建镜像,上传镜像,使用新镜像重启容器。咱们会分段讲解脚本,固然你只须要把本文的脚本段落组合起来,即可以执行自动化部署了。apache
假设咱们的 apache 文件在 apache/ 子目录,一个监控程序在 monitoring/ 子目录。bash
假设咱们的脚本名称为 deploy.sh
,使用以下命令进行初始化:服务器
#!/bin/bash set -e REMOTE_USERNAME="..." REMOTE_HOST="..." IMAGE_REPOSITORY="my_repository"
前面两个变量并不须要解释,后面上传镜像的时候用的到。
最后一个变量是 Docker 镜像的名称,你须要设置本身的镜像名称,在后面咱们也会有这个名称进行检测。架构
再后文中咱们会创建同一个名称可是 tag 不一样的两个镜像分别存储 apache 和 monitor。ssh
第一件要作的事情即是构建镜像,构建过程和普通的 Docker 命令同样。咱们写了一个函数专门用来构建镜像:函数
function build_image { docker build -t $IMAGE_REPOSITORY:$1 $2 } build_image apache apache/ build_image monitoring monitoring/
咱们使用上面的已经定义的 IMAGE_REPOSITORY
名称命名镜像,而且对咱们的两个 apache 和 monitoring 镜像贴标签。
固然本专栏的前文中提到,镜像能够输出到文件,也能够由文件输入。固然也能够从标准输入输出流进行输入输出。咱们使用标准输入输出流和管道进行操做。这个输入和上传的操做很容易用一行 shell 语句写出来。
docker save $IMAGE_REPOSITORY:$1 | bzip2 | pv | ssh $REMOTE_USERNAME@$REMOTE_HOST 'bunzip2 | docker load'
固然,成熟的程序员都会写个函数,顺便作作重复性检测,毕竟几百 M 的文件呢,上传都要很久,还能节省带宽。尤为是有不少镜像须要上传的时候,万一有几个重复的呢。咱们所须要的就是按照镜像名称和标签列出本机和远程服务器上的 Docker 容器的 ID,而后检测他们的 ID 是否相同。
本节的 shell 脚本以下。
function upload_image_if_needed { if [[ $(ssh $REMOTE_USERNAME@$REMOTE_HOST "docker images $IMAGE_REPOSITORY | grep $1 | tr -s ' ' | cut -d ' ' -f 3") != $(docker images $IMAGE_REPOSITORY | grep $1 | tr -s ' ' | cut -d ' ' -f 3) ]] then echo "$1 image changed, updating..." docker save $IMAGE_REPOSITORY:$1 | bzip2 | pv | ssh $REMOTE_USERNAME@$REMOTE_HOST 'bunzip2 | docker load' else echo "$1 image did not change" fi } upload_image_if_needed apache upload_image_if_needed monitoring
上面说的是更新镜像,本节讲的是更新容器。
如今是最后一步,咱们须要使用新镜像重启容器。固然,和其余的语言同样,咱们能够将远程主机上的命令写成本机上的输入形式:
ssh -tt $REMOTE_USERNAME@$REMOTE_HOST << EOF ... exit EOF
而后判断容器是否存在,若是存在就结束容器。
docker rm -f ${IMAGE_REPOSITORY}_apache || true docker rm -f ${IMAGE_REPOSITORY}_monitoring || true
注:可能有读者对 docker rm -f ${IMAGE_REPOSITORY}_apache
这条命令感到不解,在此解释一下。原文做者使用制定名称 ${IMAGE_REPOSITORY}_apache
对容器进行命名。
||
是必需的,由于若是容器不存在的话,docker rm
命令便会返回一个错误。咱们只须要删除容器,并不去判断他们是否存在。不存在的也就不用删除,固然,删除也没问题。
下面一步即是启动容器:
docker run -d --name ${IMAGE_REPOSITORY}_apache $IMAGE_REPOSITORY:apache docker run -d --name ${IMAGE_REPOSITORY}_monitoring $IMAGE_REPOSITORY:monitoring
为了便于阅读,我特地整理了全部脚本的彻底版,以下:
#!/bin/bash set -e REMOTE_USERNAME="..." REMOTE_HOST="..." IMAGE_REPOSITORY="my_repository" function upload_image_if_needed { if [[ $(ssh $REMOTE_USERNAME@$REMOTE_HOST "docker images $IMAGE_REPOSITORY | grep $1 | tr -s ' ' | cut -d ' ' -f 3") != $(docker images $IMAGE_REPOSITORY | grep $1 | tr -s ' ' | cut -d ' ' -f 3) ]] then echo "$1 image changed, updating..." docker save $IMAGE_REPOSITORY:$1 | bzip2 | pv | ssh $REMOTE_USERNAME@$REMOTE_HOST 'bunzip2 | docker load' else echo "$1 image did not change" fi } function build_image { docker build -t $IMAGE_REPOSITORY:$1 $2 } build_image apache apache/ build_image monitoring monitoring/ upload_image_if_needed apache upload_image_if_needed monitoring ssh -tt $REMOTE_USERNAME@$REMOTE_HOST << EOF docker rm -f ${IMAGE_REPOSITORY}_apache || true docker rm -f ${IMAGE_REPOSITORY}_monitoring || true docker run -d --name ${IMAGE_REPOSITORY}_apache $IMAGE_REPOSITORY:apache docker run -d --name ${IMAGE_REPOSITORY}_monitoring $IMAGE_REPOSITORY:monitoring exit EOF
Docker 确实是容器中的佼佼者,并且有很好的命令行支持,可是目前仍是缺乏能便捷部署 Docker 容器的方式。固然,经过几段简单的脚本,咱们即可以解决这个问题。我但愿这些脚本也能帮助到你。
本文对容器的操做比较简单粗暴,使用 docker rm
命令进行强行删除,可能会致使一段时间(通常不到半分钟,视状况而定)的网站 403,404 或者 503。
除此以外,本文的 shell 操做能够当成是 shell 远程执行命令的范例。
本专栏将继续推出 Docker 系列文章,欢迎关注。