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. Codeforces Round #440(Div.2)

    一句话题意: A:给出两个长为\(n\),\(m\)的的数组,每个数在\(1\)到\(9\)之间,求出一个最小的数使得至少有一位出现在一个数组中,且至少有一位出现在另一个数组中.\(n,m\leq9\ ...

  2. service中显示一个dialog

    dialog是依附于activity存在的.但是app中经常需要使用以下的情况,在service中做一些后台操作,在某个临界条件满足时,显示一个dialog告知用户.这时dialog无法直接从serv ...

  3. ZJOI2017D1

    假装我还活着. 去温州前沉迷各种奇怪的动画片..嗯补了不少高达.. 到温州以后继续看片..嗯ZG还是挺不错的..然后接着就FA♂现我什么都不会写..有点尴尬.. 因为宾馆离温州中学比较远就完全没去听课 ...

  4. android在JNI_OnLoad入口函数下断点动态调试so库

    一般来说,很多APK的校验代码,都会在程序运行的时候自动加载一些动态so库,然后执行这些库中的校验代码.所以为了能够通过程序的校验,我们必须在执行这些函数之前下断点——理想的方法就是在JNI_OnLo ...

  5. Python之文件操作:文件的读写

    一.open函数:对文件读写之前,需要先打开文件,获取文件句柄 注意:open() file() 尽量使用open(),Python3以后不支持file()了 1.open(file_name[,ac ...

  6. 在 CentOS 7 中以命令行方式安装 MySQL 5.7.11 for Linux Generic 二进制版本

    MySQL 目前的最新版本是 5.7.11,在 Linux 下提供特定发行版安装包(如 .rpm)以及二进制通用版安装包(.tar.gz).一般情况下,很多项目都倾向于采用二进制通用安装包形式来进行安 ...

  7. Codeforces Round #466 (Div. 2) A. Points on the line[数轴上有n个点,问最少去掉多少个点才能使剩下的点的最大距离为不超过k。]

    A. Points on the line time limit per test 1 second memory limit per test 256 megabytes input standar ...

  8. ELK之filebeat收集多类型日志

    1.IP规划 10.0.0.33:filebeat+tomcat,filebeat收集系统日志.tomcat日志发送到logstash 10.0.0.32:logstash,将日志写入reids(in ...

  9. Java死锁及解决

    Java线程死锁如何避免这一悲剧  Java线程死锁需要如何解决,这个问题一直在我们不断的使用中需要只有不断的关键.不幸的是,使用上锁会带来其他问题.让我们来看一些常见问题以及相应的解决方法: Jav ...

  10. Atcoder Contest 015 E

    题目大意 给定一条数轴. 数轴上有\(n\)个点, 它们的初始位置给定, 移动速度也给定. 从0时刻开始, 所有点都从其初始位置按照其移动速度向数轴正方向移动. 这些点开始时可能是红色的, 也可能是黑 ...