Original URL:https://advancedweb.hu/2015/04/14/deploying-docker-images-via-ssh/

Background

When we began Dockerizing this blog for good, I began to look for ways to automate the build and deployment process. It turned out that although Docker is an excellent container for running applications, there is no standard way to update a server. Luckily with a moderately complex shell script it is indeed doable, and can be fully automated.

Our current architecture is made of several dependent Docker images and a Linux box as a production server. Luckily we have no dynamic data, but the deploy script can easily be modified to handle those too. In that case we would use thedata only containerapproach.

So, let’s build our deployment script!

The script

The basic idea of the build script is simple: Build the images, upload them to the server, then restart the containers with the new versions. These are the building blocks, just need some tricks to mix in order to be able to fully automate the process.

For the sake of example, let’s say we have an apache app in the apache/ subdirectory and a monitoring app residing in monitoring/.
Setting up

Let’s name our script deploy.sh and add some bootstrapping:

#!/bin/bash

set -e

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

The last variable will be the repository name for the Docker images. It is important to add one, as we will use it for the up-to-date check later.
Building

The first thing to do is to build the images. It has nothing interesting, just a standard Docker build:

function build_image {
docker build -t $IMAGE_REPOSITORY:$ $
} build_image apache apache/
build_image monitoring monitoring/

It builds the image to the predefined repository and adds a tag for easy retrieval.
Uploading to the remote server

Fortunately Docker can save and load an image to/from the standard input stream, so it makes piping possible. It effectively makes the whole uploading a one-liner.

docker save $IMAGE_REPOSITORY:$ | bzip2 | pv | ssh $REMOTE_USERNAME@$REMOTE_HOST 'bunzip2 | docker load'

What we should implement is to first check whether the image was actually modified or not. As Docker images tends to weight several hundred megabytes, it can save a lot of bandwidth, especially when there are several images and only a few of them are changing. The idea is that we can list the images for a given repository, then extract the image ID, then do the same on the remote machine, and if the IDs are the same, then the images are the same.

The finished part looks like this:

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 $ | tr -s ' ' | cut -d ' ' -f ) ]]
then
echo "$1 image changed, updating..."
docker save $IMAGE_REPOSITORY:$ | 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

Updating the containers

The last step is to restart the containers using the new images. The good thing is that we can embed remote bash commands in our deploy script and treat them just like the local ones:

ssh -tt $REMOTE_USERNAME@$REMOTE_HOST << EOF

...

exit
EOF

The first thing is to kill the current containers if they exist:

docker rm -f ${IMAGE_REPOSITORY}_apache || true
docker rm -f ${IMAGE_REPOSITORY}_monitoring || true

The || true is needed, because if the conta

iner does not exists, then docker rm gives back an error. Since we just want to have the containers killed, in case they did not exist in the first place, doing nothing is perfectly fine.

The second step is to start the containers, the standard way:

docker run -d --name ${IMAGE_REPOSITORY}_apache $IMAGE_REPOSITORY:apache
docker run -d --name ${IMAGE_REPOSITORY}_monitoring $IMAGE_REPOSITORY:monitoring

The final script

For a better overview, here is the complete script:

#!/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 $ | tr -s ' ' | cut -d ' ' -f ) ]]
then
echo "$1 image changed, updating..."
docker save $IMAGE_REPOSITORY:$ | 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:$ $
} 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

Conclusion

Docker is a fascinating container technology that allows building works-everywhere apps, and it comes with good CLI support. It currently lacks the features to make deploying easy, but with some scripting magic, we can work around these issues. I hope the above script gives some insight and possibly a solution to people facing the same problem.

Deploying Docker images via SSH的更多相关文章

  1. Docker创建支持ssh服务的容器和镜像

    原文链接:Docker创建支持ssh服务的容器和镜像 1. 这里使用的centos作为容器,所以首先下载centos的images # sudo docker pull centos 2. 下载后执行 ...

  2. 配置docker容器上ssh无密登录

    配置docker容器上ssh无密登录 1.修改所有容器中root账户密码 ssh到远程主机时,首次需要密码访问,因此需要修改root账号密码. 密码必须要8位以上字母数字混合. $>passwd ...

  3. Docker 添加容器SSH服务

    很多时候我们需要登陆到容器内部操作,此时我们就需要开启容器的SSH支持了,下面的小例子将具体介绍三种分配IP地址的方法,分别是pipworl分配,commit分配,Docker分配等. 基于commi ...

  4. docker中安装ssh服务

    系统:Debian Docker 目标:在docker(debian系统)中安装ssh服务,实现远程登陆和控制docker 步骤: 初始状态:通过docker pull debian得到的一个debi ...

  5. Centos7下,简单DOCKER 使用.映射SSH端口到宿主主机.

    其实使用docker完全没有必要ssh,初学的时候,可以这样熟悉以下操作. 参考这哥们的文章:http://www.jianshu.com/p/d2dd936863ec 获取镜像 docker pul ...

  6. Deploying docker registry v2

    生成证书 openssl genrsa -out mydomain.key 2048 生成秘钥 openssl req -newkey rsa:4096 -nodes -sha256 -keyout ...

  7. 配置docker中免密码SSH

    更换docker国内镜像,使用DaoCloud,特别快 编写Dockerfile文件 FROM ubuntu MAINTAINER ggzone xxx@live.com ENV REFRESHED_ ...

  8. 为Docker镜像添加SSH服务

    一.基于commit命令创建 1. 首先下载镜像 $ docker run -it ubuntu:16.04 /bin/bash 2. 安装SSH服务 #更新apt缓存 root@5ef1d31632 ...

  9. stackstorm docker中配置ssh免密码登录方式

    在docker中配置st2的ssh登录方式折腾了好久,今天终于彻底搞懂了如何重启容器后也不丢失之前的配置,只要容器起来后就可以正常ssh 执行st2中的remote-shell-script 和rem ...

随机推荐

  1. 【CCF】炉石传说 模拟

    #include<iostream> #include<cstdio> #include<string> #include<cstring> #incl ...

  2. nodeJS(2)深了解: nodeJS 项目架构详解(app.js + Express + Http)

    简略了解:nodeJS 深了解(1): Node.js + Express 构建网站预备知识 环境: 环境: win7 + nodeJS 版本(node): 新建 nodeJS 项目: 名称为: te ...

  3. 【转】Resharper上手指南

    原文发布时间为:2011-02-16 -- 来源于本人的百度文章 [由搬家工具导入] 我是visual studio的忠实用户,从visual studio 6一直用到了visual studio 2 ...

  4. [LeetCode] Reverse Bits 位操作

    Reverse bits of a given 32 bits unsigned integer. For example, given input 43261596 (represented in ...

  5. mybatis hashmap 输入键值对为空时,key 丢失

    参考文档:https://blog.csdn.net/lulidaitian/article/details/70941769 springMVC+mybatis查询数据,返回resultType=” ...

  6. class.getDeclaredFields()与class.getFields()

    * getFields()与getDeclaredFields()区别:getFields()只能访问类中声明为公有的字段,私有的字段它无法访问.getDeclaredFields()能访问类中所有的 ...

  7. Day 26 python 正则表达式

    re模块\正则表达式 一.元字符 1.. ^ $ * + ? { } [ ] | ( ) \ "." 代表(任意一个字符) "*" 代表(任意数量任意字符,0- ...

  8. C语言联合体

    C语言联合体Unions实例代码教程 - 联合是一种特殊的数据类型在C语言中,使您可以存储不同的数据类型相同的内存位置. 联合是一种特殊的数据类型在C语言中,使您可以存储不同的数据类型相同的内存位置. ...

  9. 通用mapper的框架

    这两个框架都是一个大神写的.用来做单表的增删改查,爽爽的. 但是复杂的查询还不知道如何用,所以我还按传统的方式 写 service maperr ,写SQL来处理复杂查询,与多表的查询.  它的复杂查 ...

  10. HDFS写文件过程分析

    转自http://shiyanjun.cn/archives/942.html HDFS是一个分布式文件系统,在HDFS上写文件的过程与我们平时使用的单机文件系统非常不同,从宏观上来看,在HDFS文件 ...