使用 SSH 和 shell 脚本部署 Docker 镜像

clipboard.png

译者按:在本专栏的前面的文章中,我们已经提到过使用 Docker 的基本方法,因此本次讲解一下 使用 SSH 和 shell 脚本进行 Docker 镜像的自动化部署,原文仅供参考,因为对于 Docker 镜像,我们可以有更好的解决方案:Docker Registry Hub。但是,本文仍然可以作为 shell 脚本的参考范例。

背景

当我们将本站转移到 Docker 容器内之后,我一直在寻求能进行自动化构建和部署镜像的方法。毫无疑问,Docker 本身是一个非常完美的应用容器,但是 Docker 并没有提供能够自动化更新镜像的标准方法。当然,我写了一些 shell 脚本,实现了 Docker 容器镜像的自动化部署。

我们假设基础架构是一台 Linux 宿主机和几个独立的 Docker 镜像,没有网站运行时产生的动态文件,例如用户上传的文件。
当然,要解决这些动态文件也非常简单,本篇文章中的脚本只需要修改一小部分,然后加上 data only container 便可以完美解决动态文件的问题。

那么,我们开始进行自动化部署吧。

脚本

脚本的初衷非常简单:构建镜像,上传镜像,使用新镜像重启容器。我们会分段讲解脚本,当然你只需要把本文的脚本段落组合起来,便可以执行自动化部署了。

假设我们的 apache 文件在 apache/ 子目录,一个监控程序在 monitoring/ 子目录。

设置环境

假设我们的脚本名称为 deploy.sh,使用如下命令进行初始化:

#!/bin/bash

set -e

REMOTE_USERNAME="..."
REMOTE_HOST="..."
IMAGE_REPOSITORY="my_repository"

前面两个变量并不需要解释,后面上传镜像的时候用的到。
最后一个变量是 Docker 镜像的名称,你需要设置自己的镜像名称,在后面我们也会有这个名称进行检测。

再后文中我们会建立同一个名称但是 tag 不同的两个镜像分别存储 apache 和 monitor。

构建

第一件要做的事情便是构建镜像,构建过程和普通的 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 系列文章,欢迎关注。

阅读 12.7k

推荐阅读
大舒的博客
用户专栏

我都不写PHP了你们还挤兑我。。

139 人关注
36 篇文章
专栏主页