在Docker里使用(支持镜像继承的)supervisor管理进程(转)
这篇文章是受 dockboard 之托帮忙翻译的与 docker 有关的技术文章。译自 Using Supervisor with Docker to manage processes (supporting image inheritance) ,作者 Quinten Krijger。
![]()
在八月份,我写了一篇关于如何创建 tomcat 镜像的 blog 。从那以后,docker 又改进了很多,我对 docker
的了解也增加了很多。我很高兴和你分们享我找到的关于管理 container 进程的好办法。在读完这篇文章后,我希望你能善加利用我 github
仓库 里的 supervisor 镜像。
Docker 命令
在之前的文章里,我提到 Docker(只能)支持运行一个前台进程。我们通常习惯使用类似 upstart 这种管理服务来初始化启动流程,但是
Docker 默认没有这些服务的支持。刚开始使用 Docker
时会很不习惯,你必须指定你想要运行的进程。这种行为和虚拟机相比有个优点,会尽可能的保持轻量的 container。你可以通过 run
命令最后的参数,在启动 container 时指定进程命令,比如:
docker run ubuntu echo "hello world"
另外一种方法,你可以利用 CMD 指令,在 Dockerfile 里指定 docker run 命令的默认参数。比如,如果你目录下的 Dockerfile 包含以下内容:
FROM ubuntu
CMD echo "hello world"
再使用下面的指令构造 hello_world_printer 镜像:
docker build -t "hello_world_printer" .
使用下面的命令,你可以得到和之前 run 命令相同的执行结果。
docker run hello_world_printer
要注意,因为你可以覆盖掉 CMD 指定的命令行参数,这个只是个运行时的指令。有趣的事情是,在 Linux container 里,你可以只调用 upstart 命令然后得到和普通虚拟机大致相同的行为。
运行多个命令
运行多个进程是个很正常的想法。比如,一个 ssh 服务(这样就能登录到正在运行的 container)和实际的应用。你可以用下面的方法运行 container:
docker run ... /usr/sbin/sshd && run_your_app_in_foreground
这在开发时很方便。这样,当应用进程退出后,因为唯一的前台程序退出了,container 会自动关闭。当然你可以使用 using
/usr/bin/sshd -D 保证 container 不会退出,但是这里真正的问题是,这种使用 run
命令设置初始程序的方式不够简洁。而且,随着你的 container 变复杂,run 命令会越来越长。
所以,在运行更复杂的 container 的时候,很多人使用复杂的 bash 脚本。典型的 bash
脚本会执行一个前台进程,并开启一个或者多个(renegade)守护进程。与只是用 Docker
命令行的方式相比,这种方法最重要的改进在于,bash 脚本是可以做版本控制的:启动脚本在你的 Docker
镜像里,新的改动可以和软件项目一起分发。不过,使用 bash 脚本管理进程依旧简陋枯燥,而且容易出错。
……使用 supervisor
更好的方法是使用 supervisor 。supervisor
可以更好的管理进程:使用更加简洁的代码管理进程;在崩溃时可以重启进程;允许重启一组进程并且有命令行工具和网页界面来管理进程。当然,越大的能力要求
越大的责任:大量使用 supervisor 特性的代码,预示着你应该将整个服务更好的拆分成多个小的 supervisor 来管理。
个人来讲,我喜欢 supervisor
让我用更清晰的代码管理启动的进程。我见过最简洁的使用例子,是子镜像扩展出一个进程组。比如,如果你经常使用 SSH,使用一个 SSH
镜像作为基础镜像就是很合理的。这种情况,在所有基于这个镜像的扩展镜像上实现启动 SSH
进程的代码,形式少就是一种重复代码。我来给你们展示下我找到的解决这个问题的好办法。
supervisor 基础镜像
首先,因为我默认使用 supervisor,所以我所有的镜像都扩展自一个只包含 supervisor 和最新版本 ubuntu
的基础镜像。你可以在 这里 找到这个 Dockerfile。这个基础镜像包括一个配置文件 /etc/supervisor.conf :
[supervisord]
nodaemon=true
[include]
files = /etc/supervisor/conf.d/*.conf
这个配置让 supervisor 本身以前台进程运行,这样可以让我们的 container 启动后持续运行。第二,这个配置将包含所有在 /etc/supervisor/conf.d/ 目录下的配置文件,启动任何在这里定义的程序。
扩展基础镜像
![]()
是的,想法很简单。所有的子 container 通过将特定的 service.sv.conf 放到特定的目录的方式,将其自己的服务加入到 supervisor 的管理里。之后,使用如下命令启动 container:
docker run child_image_name "supervisor -c /etc/supervisor.conf"
会自动启动所有指定的进程。你可以对镜像做多层扩展,每层扩展加入一个或者多个服务到配置目录。在 Docker 里使用 supervisor 启动命令代替 upstart 也更有效和有范。
作为例子,让我们看看之前 blog 提到的 Tomcat 工作栈,是如何使用这种改进后的方法的。
- 首先,和之前讨论的一样,我们使用从 ubuntu 扩展而来的 supervisor 基础镜像
- 之后,我们使用在 supervisor 上安装了 Java 的 JDK 镜像 。Java 只是其他服务使用的库,所以我们在这层不指定任何启动服务。这层要做一些类似设置 JAVA_HOME 环境变量的通常任务
- Tomcat 镜像在工作栈上安装 Tomcat 并暴露 8080 端口。这层包括一个名字是 Tomcat 的服务,定义在 tomcat.sv.conf :
[program:webapp] command=/bin/bash -c "env > /tmp/tomcat.env && cat /etc/default/tomcat7 >> /tmp/tomcat.env && mv /tmp/tomcat.env /etc/default/tomcat7 && service tomcat7 start" redirect_stderr=true
执行 Tomcat 服务的命令并不像我喜欢的那样简洁,将其放到一个专门的脚本里会更好。命令先添加了一些环境变量,比如 container
的关联参数 ,到 /etc/default/tomcat7 ,这样我们可以在之后的配置中使用这些参数,后面的例子会展示这种用法。也许使用类似
etcd 的键值存储会更好,不过这超出了本文的范畴。
当然,我们这里只安装了默认的文件,没有真正的网络应用程序。- 你的网络应用程序应当扩展自 Tomcat 镜像,并安装入真正的应用程序。当启动 supervisor 的时候,会自动启动 Tomcat。
一个 Tomcat 网络程序的 Dockerfile 例子
如何安装实际的网络应用超出了本文的范畴,不过,作为结束,我给出了个 Dockerfile 例子,演示如何使用这个工作栈。这个例子完全基于 Java Tomcat,所以如果你对这个不感兴趣,别读了,玩别的去吧:)
假设,我们有一个使用 Elasticsearch 的网络应用:
FROM quintenk/tomcat:
# 安装一些项目的依赖,这些依赖在每次更新时不会改变
# RUN apt-get -y install ...
RUN rm -rf /var/lib/tomcat7/webapps/*
# 将配置加入 /etc/default/tomcat7,比如:
...
RUN echo 'DOCKER_OPTS="-DELASTICSEARCH_SERVER_URL=${ELASTICSEARCH_PORT_9200_TCP_ADDR}"' >> /etc/default/tomcat7
RUN echo 'CATALINA_OPTS="... ${DOCKER_OPTS}"' >> /etc/default/tomcat7
# 加入类似 log4j.properties 的配置文件,并将其 chown root:tomcat7
# 假设项目已经构建好了,而且 ROOT.war 在你构建 Docker 的目录(包含 Dockerfile 的目录)。基于缓存的考虑,这个作为最后的步骤
ADD ROOT.war /var/lib/tomcat7/webapps/
RUN chown root:tomcat7 /var/lib/tomcat7/webapps/ROOT.war
CMD supervisord -c /etc/supervisor.conf
In
this code, the variables for elasticsearch (a search index), are set
because the Supervisor configuration for Tomcat prepends all variables
to the /etc/default/tomcat7 file at start-up time. Of course, we would
need to start the webapp with a link to the elasticsearch container:
e.g. 这段代码里,elasticsearch 的相关环境变量(搜索索引)已经被设置了,因为 supervisor 关于 Tomcat
的配置,会在启动时将所有环境变量添加到 /etc/default/tomcat7。当然,我们在启动网络应用镜像时需要关联到
elasticsearch containter,比如:
docker run -link name_of_elasticsearch_instance:elasticsearch -d name_of_webapp_image "supervisor -c /etc/supervisor.conf"
你现在的网络应用可以去访问 ELASTICSEARCH_SERVER_URL 路径了。你可以在配置文件里使用这个变量,像这样:
FROM ubuntu
CMD echo "hello world"
这样就可以将配置暴露给你的应用程序。如果你是个 Java 开发者,并且也阅读了前一篇文章,希望这让你能开始一段愉快的代码之旅。
在Docker里使用(支持镜像继承的)supervisor管理进程(转)的更多相关文章
- 【云计算】使用supervisor管理Docker多进程-ntpd+uwsgi+nginx示例最佳实践
supervisor安装启动: apt-get install supervisor -y # start supervisord nodaemon /usr/bin/supervisord --no ...
- Docker 最常用的镜像命令和容器命令
本文列出了 Docker 使用过程中最常用的镜像命令和容器命令,以及教大家如何操作容器数据卷,实现容器数据的备份.熟练练习这些命令以后,再来一些简单的应用部署练习,大家就可以学习 Docker 的镜像 ...
- LindDotNetCore~docker里图像上生成中文乱码问题
回到目录 因为docker上的大部分镜像都是基于linux系统的,所以在向图像中写中文时需要考虑中文字体问题,例如在microsoft/aspnetcore2.0这个镜像,它是基于debian系统的, ...
- 在 Docker 里跑 Java,你必须知道的那些事儿!(转)
原文 https://www.jianshu.com/p/0897d0581872 背景:众所周知,当我们执行没有任何调优参数(如“java-jar mypplication-fat.jar”)的 J ...
- MySQL 到底能不能放到 Docker 里跑?
https://weibo.com/ttarticle/p/show?id=2309404296528549285581 前言 前几月经常看到有 MySQL 到底能不能放到 Docker 里跑的各种讨 ...
- Docker学习笔记之使用 Docker Hub 中的镜像
0x00 概述 自己编写 Dockerfile 能够很好的实现我们想要的程序运行环境,不过如果装有我们想要环境的镜像已经由热心的开发者构建好并共享在 Docker Hub 上,直接使用它们就会远比自己 ...
- Docker基础修炼2--Docker镜像原理及常用命令
通过前文的讲解对Docker有了基本认识之后,我们开始进入实战操作,本文先演示Docker三要素之镜像原理和相关命令. 本文的演示环境仍然沿用上一篇文章在本地Centos7中安装的环境,如果你本地没有 ...
- Docker学习笔记:镜像、容器、数据卷
核心概念 镜像:一个只读的模板,类似虚拟机的镜像. 容器:可以理解为镜像的一个运行实例.运行时类似于沙箱,多个容器互相独立. 仓库:存放镜像文件的地方. 镜像 命令表格 命令 解释 选项 docker ...
- Docker最常用的镜像命令和容器命令
一.镜像相关命令 官方文档:https://docs.docker.com/referenc 1.1查看镜像 [root@localhost ~]# docker images REPOSITORY ...
随机推荐
- [BZOJ1305][CQOI2009]跳舞(网络流)
1305: [CQOI2009]dance跳舞 Time Limit: 5 Sec Memory Limit: 162 MBSubmit: 3944 Solved: 1692[Submit][St ...
- Codeforces 961E 主席树
题意: 给出一个n个数的序列,求有几对(i,j)满足a[i]>=j&&a[j]>=i,(i,j)和(j,i)只能算一对. 考虑第i个数会有几个j(j<i)满足条件,首 ...
- HDU 6040 Hints of sd0061(nth_element)
[题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=6040 [题目大意] 给出一个随机数生成器,有m个询问,问第bi小的元素是啥 询问中对于bi< ...
- 【随机化】Petrozavodsk Summer Training Camp 2016 Day 5: Petr Mitrichev Contest 14, Saturday, August 27, 2016 Problem I. Vier
给你一个1~n的排列,让你找出4个下标a b c d,满足 (a+b)%n=(c+d)%n (w(a)+w(b))%n=(w(c)+w(d))%n,并且是非平凡解. 发现对于每个数i,找出两个数和为其 ...
- 【递推】【组合数】【容斥原理】UVA - 11806 - Cheerleaders
http://www.cnblogs.com/khbcsu/p/4245943.html 本题如果直接枚举的话难度很大并且会无从下手.那么我们是否可以采取逆向思考的方法来解决问题呢?我们可以用总的情况 ...
- Nginx配置自签名的SSL证书(转载)
要保证Web浏览器到服务器的安全连接,HTTPS几乎是唯一选择.HTTPS其实就是HTTP over SSL,也就是让HTTP连接建立在SSL安全连接之上. SSL使用证书来创建安全连接.有两种验证模 ...
- 从co到koa01-co
thunk 他的发展是由函数的求值策略的分歧决定的,两种求值策略 传值调用,在进入函数体之前就直接执行完,把值传进去 传名调用,将表达式传入函数体,只在用到他的时候求值 传名函数的编译器实现,其实就是 ...
- android基础知识复习——RelativeLayout布局属性、背景、半透明设置(XML设置)
转自:http://blog.csdn.net/fansongy/article/details/6817968 复习布局与XML,写了一个空的登录界面.XML的注释我写在当行的后面了.程序运行图: ...
- PHP的方法重载实现
PHP提出面向对象以来,就有着各种各样的问题,其中,不直接支持对象方法重载就是一个让人纠心的问题,在其他语言里面,大可以有以下写法(以下是C++写法): class Abc(){ public fun ...
- JavaScript 创建类/对象的几种方式
在JS中,创建对象(Create Object)并不完全是我们时常说的创建类对象,JS中的对象强调的是一种复合类型,JS中创建对象及对对象的访问是极其灵活的. JS对象是一种复合类型,它允许你通过变量 ...