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. 【13】vuex2.0 之 state

    Vuex 的核心是 store, 它是一个通过 Vuex.Store 构造函数生成的对象.为什么它会是核心呢?因为我们调用这个构造函数创建store 对象的时候,给它传递参数中包装了state, mu ...

  2. SQL索引碎片整理脚本

    原文发布时间为:2011-02-23 -- 来源于本人的百度文章 [由搬家工具导入] reindex是比较好的选择,速度快,但是他不能在线操作INDEXDEFRAG 比较慢,但是可以在线操作rebui ...

  3. AVRStudio 6 设置F_CPU时钟频率

    具体如下: 1>右键项目属性 2>根据语言选择一下,C或C++

  4. Day 20 Object_oriented_programing(摘)

    面向对象变成介绍 面向过程编程 核心是过程(流水线式思维),过程即解决问题的步骤,面向过程的设计就好比精心设计好一条流水线,考虑周全什么时候处理什么东西.主要应用在一旦完成很少修改的地方,如linux ...

  5. c# Thread类

    现在C#已经建议摈弃使用 Suspend, Resume 暂停/恢复线程, 也尽量少用 Abort方法中断一个线程. 建议使用线程的同步手段有:  Mutex.ManualResetEvent.Aut ...

  6. hdu 4541(麻烦的模拟)

    Ten Googol Time Limit: 500/200 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)Total Su ...

  7. HDFS读文件过程分析:读取文件的Block数据

    转自http://shiyanjun.cn/archives/962.html 我们可以从java.io.InputStream类中看到,抽象出一个read方法,用来读取已经打开的InputStrea ...

  8. POJ 1067 取石子游戏 [博弈]

    题意:威佐夫博弈. 思路:看了很多证明都没看懂.最后决定就记住结论好了. 对于所有的奇异局面(必败局),有通项公式 Pi = (a, b), (a = i * [(sqrt(5) + 1) / 2], ...

  9. Android-Handler消息机制实现原理

    一.消息机制流程简介 在应用启动的时候,会执行程序的入口函数main(),main()里面会创建一个Looper对象,然后通过这个Looper对象开启一个死循环,这个循环的工作是,不断的从消息队列Me ...

  10. linux grep 搜索查找

    查找关键字在哪些文件夹中的哪些文件中出现(只列出文件名称): grep -l 15386257298 */* 查找关键字在哪些文件夹中的哪些文件中出现(列出文件名称+关键字): grep -o 153 ...