资讯专栏INFORMATION COLUMN

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

stormzhang / 3128人阅读

摘要:译者按在本专栏的前面的文章中,我们已经提到过使用的基本方法,因此本次讲解一下使用和脚本进行镜像的自动化部署,原文仅供参考,因为对于镜像,我们可以有更好的解决方案。我们使用标准输入输出流和管道进行操作。

  

译者按:在本专栏的前面的文章中,我们已经提到过使用 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 系列文章,欢迎关注。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/26409.html

相关文章

  • 如何使用DockerDocker-ComposeRancher搭建部署Pipeline(二)

    摘要:目前我们正采取措施,通过逐步改善现有过程来实现持续部署。在这篇文章中,我们将看看如何使用和来改善此设计。通过使用,在未来我们可以轻松地将构建和部署任务集成起来,从而得到额外的好处。月日,北京海航万豪酒店,容器技术大会即将举行。 在这一系列文章的第一篇中,我们分享了只用Docker时我们开发的初步的工作流,如何创建一个基础的构建和部署流水线。容器的部署方式不再是在登陆server的时候从...

    LancerComet 评论0 收藏0
  • 使用Packer实现自动化构建UCloud云主机镜像

    摘要:宋体为了解决此类问题,开发了相关代码,并被自动化构建镜像工具的官方仓库所采纳。宋体宋体可以运行在常用的主流操作系统上,它不是等软件的替代品,而是集成并使用这些自动化配置工具在镜像上预装软件等。背景 云主机是用户使用最高频的云产品之一。随着云主机数量的增多,如何在云主机中保证版本化部署的一致性,成为用户常见的难题。在现有情况下,用户首先需要手动或使用脚本连接主机,然后再进行部署安装,操作...

    zorpan 评论0 收藏0
  • 如何用 Docker 实现 PHP 命令行程序的 CI/CD

    摘要:数人云今天带来的文章将分享如何用实现命令行程序的过程中整体思路以及需要注意哪些问题。月日,超越传统运维之道的话题将在北京延续,四位业界大牛技术齐聚,结合传统运维现状及实践案例,讲述的超越之道。 数人云今天带来的文章将分享如何用Docker实现PHP命令行程序的CI/CD过程中整体思路以及需要注意哪些问题。 6月10日,《DevOps&SRE超越传统运维之道》的话题将在北京延续,四位业界...

    Pink 评论0 收藏0
  • 如何用 Docker 实现 PHP 命令行程序的 CI/CD

    摘要:数人云今天带来的文章将分享如何用实现命令行程序的过程中整体思路以及需要注意哪些问题。月日,超越传统运维之道的话题将在北京延续,四位业界大牛技术齐聚,结合传统运维现状及实践案例,讲述的超越之道。 数人云今天带来的文章将分享如何用Docker实现PHP命令行程序的CI/CD过程中整体思路以及需要注意哪些问题。 6月10日,《DevOps&SRE超越传统运维之道》的话题将在北京延续,四位业界...

    stdying 评论0 收藏0
  • Node项目的Gitlab自动部署实践(基于Docker

    摘要:只要的项目有提交,相关就根据来决定是否跑自动部署的命令。项目的自动部署添加执行的注册命令,按照说明进行参数配置。至此,和服务都已经自动部署完成。 准备工作 说明 公司最近准备了一台新的开发服务器,正好用以实践docker的基本应用。docker的好处不再赘述,详情可参考阮一峰的这篇入门。(关于Docker最好的中文介绍,没有之一)。 公司目前主要使用了EggJs + ReactJS的技...

    oysun 评论0 收藏0

发表评论

0条评论

stormzhang

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<