1. 单机运行的Docker

容器化部署是现在进行时,开源应用大多数支持容器化部署
在少量机器的场景下往往采用docker cli 和 docker-compose管理,进行“单机式管理”
机器稍多点会采用Docker Swarm群集的方式,毕竟k8s稍重
如果有更多的机器情况下一般会采用k8s的方式
在个人、创业公司、小团队的场景下我们往往在多个云、家里、vps上拥有少量虚拟机服务器,这些服务器上都运行了docker实例
虽然我们也可以用公网vpn、zerotier等方式打通各个地域的机器形成一个内网,从而构建“群集”,但实际情况是没那么多带宽,从而无法“负载均衡”,所以实际的实际还是独立使用
受限制于公网带宽很小,只能独立使用
我们也拥有一些4G移动流量接入这种EDGE边缘场景的情况,这些IoT上也运行着Docker实例
那么这些NAT内网环境下的Docker实例,公网IP环境下的Docker实例,是否能集中管理?
当然可以,用Portainer就挺方便

2. 用Portainer作为Docker实例管理平台实战步骤

2.1 主节点-Portainer server主控安装

选一个7×24小时且有公网IP的节点运行Portainer server主控

docker run -d -p 8000:8000 -p 9000:9000 --name portainer --restart always -v /var/run/docker.sock:/var/run/docker.sock -v /data/appdata/portainer:/data portainer/portainer

9000端口为web管理界面端口
8000端口为Agent接入端口
这2个端口公网IP防火墙都必须放行

浏览器打开web管理界面
http://Portainer server主控公网IP:9000

初次访问设置一个密码,设置密码后需要选择连接docker的方式
选第一个Local 然后点击Connect
默认进入Home菜单,点击这个Local本地docker实例进入其他管理

Portainer官方安装手册参考

2.2 配置https nginx代理(可选)

如果不配置https可跳过本节
http://你的公网IP:9000 默认没有https不安全
规划一个域名用于https访问例如https://portainer.iamle.com
用nginx作为接入反向代理到 http://portainerip:9000
下面为示例nginx portainer配置(其中包含需要的websocket proxy)

# portainer.iamle.com.conf
map $http_upgrade $connection_upgrade {
    default Upgrade;
    ''      close;
}
upstream portainer {
    server 127.0.0.1:9000;
}
server {
        listen       80;
        server_name portainer.iamle.com;
        return      301 https://$server_name$request_uri;
}
server {

                listen 443 ssl http2;
        server_name portainer.iamle.com;

                ssl_certificate         ssl/iamle.com.cer;
                ssl_certificate_key     ssl/iamle.com.key;
                #ssl_session_cache           shared:SSL:10m;
                #ssl_session_timeout         10m;
                #ssl_session_tickets         off;

                ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
                ssl_ciphers         HIGH:!aNULL:!MD5:!EXPORT56:!EXP;
                ssl_prefer_server_ciphers on;

        location / {
                    proxy_set_header Host              $host;
                    proxy_set_header X-Forwarded-Proto $scheme;
                    proxy_set_header X-Forwarded-Port  $server_port;
                    proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
                    proxy_set_header X-Real-IP         $remote_addr;
                    proxy_set_header X-Request-Id $request_id;
                    proxy_set_header Upgrade           $http_upgrade;
                    proxy_set_header Connection        $connection_upgrade;
                    proxy_read_timeout 60m;
                    proxy_send_timeout 60m;
                    proxy_http_version 1.1;
                    proxy_pass http://portainer;
                    break;
        }


        error_log   /data/logs/portainer.iamle.com-error.log;
        access_log  /data/logs/portainer.iamle.com.log access;

}

2.3 主节点-配置一个在NAT内网Agent客户端

前面我们已经配置好一个具有公网IP的Portainer管理控制节点
那么现在把内网(NAT、IoT)、公有云、vps等运行的Docker实例来接入控制节点管理

一图胜千言,官方介绍图

图中这个Portainer管理了2个内网的Agent
其中一个是个Swarm群集,另外一个是个单机

Portainer server上增加一个Edge Agent
Endpoints菜单 》 Add endpoint 》 Edge Agent

Name:为自定义
Portainer server URL:默认为当前Portainer server ip (如果用nginx配置了https可以使用https不加端口号)
》 Add endpoint

增加端点后出现

部署客户端agent 有2种选择 Standalone 和 Swarm
如果已经组过Swarm那么选Swarm,默认就是Standalone
先点击 “Copy command” 复制命令,在Agent客户端去执行
Public IP: 如果有可以设置,这样在以后部署了docker容器暴露的端口可以自动生成url

2.4 被管理节点-需要被管理的Docker实例客户端机

在被管理的客户端终端上执行(内网(NAT、IOT)、公网环境都可以,只要能连接上我们的Portainer server)
本例内网1台ip为 192.168.0.8的机器

docker run -d -v /var/run/docker.sock:/var/run/docker.sock -v /var/lib/docker/volumes:/var/lib/docker/volumes -v /:/host --restart always -e EDGE=1 -e EDGE_ID=6ad0f1ff-6fea-4710-97e2-513ef1066fd8 -e CAP_HOST_MANAGEMENT=1 -p 8000:80 -v portainer_agent_data:/data --name portainer_edge_agent portainer/agent:1.5.1

访问 http://192.168.0.8:8000(如果有公网ip用公网ip)
打开后会有个输入框
输入上一步获得的Join token
点击Submit 出现 Agent setup OK. You can close this page. 代表完成agent接入

回到 Portainer server管理界面等待上线

点击 iamle-lan-01 等待几秒钟

这样我们就可以管理多个docker实例了

3. 贴士

  • 如果agent运行不起来,无限重启
    需要根据docker logs portainer_edge_agent 获取到的错误信息排查, 官方github issue是个好去处
    另外发现2019年10月19日16:55:01 pull 下来的portainer/agent:latest 也运行不起来 改为 portainer/agent:1.5.1正常

  • Stacks粘贴docker-compose.yml进来后一直报version版本不对
    目前只支持version 2 改为2即可

4. 参考

Portainer Edge Agent 官方发布
Portainer内网边缘节点配置说明书PDF

如何在一个Docker中运行多个程序进程?

我们都知道Docker容器的哲学是一个Docker容器只运行一个进程,但是有时候我们就是需要在一个Docker容器中运行多个进程
那么基本思路是在Dockerfile 的CMD 或者 ENTRYPOINT 运行一个”东西”,然后再让这个”东西”运行多个其他进程
简单说来是用Bash Shell脚本或者三方进程守护 (Monit,Skaware S6,Supervisor),其他没讲到的三方进程守护工具同理

Bash Shell脚本

入口文件运行一个Bash Shell 脚本, 然后在这个脚本内去拉起多个进程
注意最后要增加一个死循环不要让这个脚本退出,否则拉起的进程也退出了
run.sh

#!/bin/bash

# start 1
start1  > /var/log/start1.log 2>&1 &
# start 2
start2 > /var/log/start2.log 2>&1 &

# just keep this script running
while [[ true ]]; do
    sleep 1
done

在Dockerfile的入口中运行run.sh

ENTRYPOINT  ["run.sh"]

用Bash Shell 的方式,任意发行版的linux都支持,缺点是不能拉起crash的进程,也就是只能拉起运行不能”守护”
如果不关心进程crash问题那么可以用这种方式

三方容器进程初始化之-dumb-init

dumb-init官方
A minimal init system for Linux containers
一个最小化的Linux容器初始化系统
dumb-init是一个简单的进程监控器和init系统,设计为在最小容器环境(如Docker)中作为PID 1运行。它被部署为一个用C编写的小型静态链接二进制文件。
Dockerfile 参考

# Runs "/usr/bin/dumb-init -- /my/script --with --args"
ENTRYPOINT ["/usr/bin/dumb-init", "--"]

# or if you use --rewrite or other cli flags
# ENTRYPOINT ["dumb-init", "--rewrite", "2:3", "--"]

CMD ["/my/script", "--with", "--args"]

ServiceMesh的数据平面Envoy Proxy的容器镜像就是使用的dumb-init

三方容器进程初始化之-tini

tini官方
A tiny but valid init for containers
容器的一个小而有效的init

三方进程守护之-Monit

Monit和Supervisor还是有很大区别的,Supervisor管理的都是前台执行的进程,Monit既可以管理前台进程也可以管理后台进程,简单的说,在CentOS中使用service xxx start 启动的程序,使用Monit可以直接管理,这就解决了很多没有前台方式启动的程序不能用Supervisor来管理的问题。
Dockerfile 参考

ENTRYPOINT ["/usr/bin/monit","-I"]

三方进程守护之-Supervisor

大名鼎鼎的 Supervisor
如果有多种版本的linux要用那么可以用Supervisor做统一进程守护管理,网上资料一大堆
注意要以前台程序运行,配置文件中要有,如果是后台的方式docker会退出

[supervisord]
nodaemon=true

Dockerfile 参考

ENTRYPOINT ["supervisord", "-c", "/etc/supervisor/conf.d/youconf.conf"]

三方进程守护之-Skaware S6

Supervisor是常见的进程守护程序,不过程序文件太大,想要容器镜像尽量小,在特别是用Alpine作为基础镜像的时候推荐使用Skaware S6
参考这个微服务基础镜像 https://github.com/nicholasjackson/microservice-basebox 他就是用 Skaware 作为进程守护程序运行多个进程的
如果基础容器镜像是本身就是Alpine,那就再合适不过了
Dockerfile 参考

# skaware s6 daemon runner
RUN mkdir /s6 \
 && wget --no-check-certificate https://github.com/just-containers/skaware/releases/download/v1.21.2/s6-2.6.1.1-linux-amd64-bin.tar.gz \
 && tar -xvzf s6-2.6.1.1-linux-amd64-bin.tar.gz --directory /s6 --strip-components=1 \
 && mv /s6/bin/* /usr/bin \
 && rm -rf s6-2.6.1.1-linux-amd64-bin.tar.gz \
 && rm -rf /s6 \
 && cd /usr/bin/ \
 && chmod -R 755 s6-accessrules-cdb-from-fs s6-accessrules-fs-from-cdb \
    s6-applyuidgid s6-cleanfifodir s6-connlimit s6-envdir s6-envuidgid \
    s6-fdholder-daemon s6-fdholder-delete s6-fdholder-deletec s6-fdholder-getdump \
    s6-fdholder-getdumpc s6-fdholder-list s6-fdholder-listc s6-fdholder-retrieve \
    s6-fdholder-retrievec s6-fdholder-setdump s6-fdholder-setdumpc s6-fdholder-store \
    s6-fdholder-storec s6-fdholder-transferdump s6-fdholder-transferdumpc s6-fdholderd \
    s6-fghack s6-ftrig-listen s6-ftrig-listen1 s6-ftrig-notify s6-ftrig-wait s6-ftrigrd \
    s6-ioconnect s6-ipcclient s6-ipcserver s6-ipcserver-access s6-ipcserver-socketbinder \
    s6-ipcserverd s6-log s6-mkfifodir s6-notifyoncheck s6-setlock s6-setsid s6-setuidgid \
    s6-softlimit s6-sudo s6-sudoc s6-sudod s6-supervise s6-svc s6-svlisten s6-svlisten1 \
    s6-svok s6-svscan s6-svscanctl s6-svstat s6-svwait s6-tai64n s6-tai64nlocal s6lockd ucspilogd \
 && cd -

# 预处理s6配置文件
RUN mkdir -p /etc/s6/.s6-svscan  \
 && ln -s /bin/true /etc/s6/.s6-svscan/finish  \
 && mkdir -p /etc/s6/cron \
 && mkdir -p /etc/s6/app \
 && ln -s /bin/true /etc/s6/cron/finish \
 && ln -s /bin/true /etc/s6/app/finish

# corotab 文件内容
ADD cronfile /var/spool/cron/root
# 运行Bash 脚本
ADD cron.run /etc/s6/cron/run
ADD app.run /etc/s6/app/run

ENTRYPOINT ["/usr/bin/s6-svscan","/etc/s6"]

cron.run example

#!/usr/bin/env bash
exec crond -n

app.run example

#!/usr/bin/env bash
exec app

三方进程守护之-s6-overlay

s6-overlay 是基于 Skaware S6适用于容器的进程守护工具
s6-overlay 官网 https://github.com/just-containers/s6-overlay
Dockerfile 参考

# Install s6-overlay 进程守护管理.
ENV S6_VERSION v1.21.4.0
RUN curl -L "https://github.com/just-containers/s6-overlay/releases/download/$S6_VERSION/s6-overlay-amd64.tar.gz" > /tmp/s6-overlay-amd64.tar.gz
RUN tar xzf /tmp/s6-overlay-amd64.tar.gz -C / --exclude="./bin" && \
    tar xzf /tmp/s6-overlay-amd64.tar.gz -C /usr ./bin \
    && rm /tmp/s6-overlay-amd64.tar.gz
ENV S6_BEHAVIOUR_IF_STAGE2_FAILS 1

# Set up a standard volume for logs.
VOLUME ["/var/log/services"]


# 设置入口为 s6-based init.
ENTRYPOINT ["/init"]

三方进程守护之-runit

runit官网http://smarden.org/runit/
具体的使用方法见官网
在Docker生态圈, phusion/baseimage-docker, gitlab 在使用runit作为进程管理工具

下面以要运行cron 和 ssh 为例
/etc/service/ 为配置文件目录

/etc/service/sshd 为要运行的程序目录
/etc/service/sshd/run 为需要运行的程序入口脚本文件
cat run

#!/bin/sh
set -e
exec /usr/sbin/sshd -D

/etc/service/cron 为要运行的程序目录
/etc/service/cron/run 为需要运行的程序入口脚本文件
cat run

#!/bin/sh
exec /usr/sbin/cron -f

Dockerfile 参考

ENTRYPOINT ["/usr/bin/runsvdir","-P","/etc/service"]

三方进程守护之-Systemd

在 docker 中使用 Systemd 需要在 docker run 的时候开启特权模式 –privileged ,所以不推荐
这个直接放弃了
Dockerfile 参考

ENTRYPOINT ["/usr/sbin/init"]

参考资料

Alpine里的go应用,你猜他能有多小? http://blog.csdn.net/sisiy2015/article/details/50350261
如何运行多进程Docker容器? http://dockone.io/article/951
在Docker Container中启动定时任务 http://dockone.io/article/1070
Docker容器内多进程管理(一)-Supervisor http://www.linuxprobe.com/docker-process-management1.html
Docker容器内多进程管理(二)-Monit http://www.linuxprobe.com/docker-process-management2.html
关于S6和Runit的论坛讨论 S6 or Runit, not systemd https://www.linuxquestions.org/questions/slackware-14/s6-or-runit-not-systemd-4175465428/
[译] runit 快速入门 https://segmentfault.com/a/1190000006644578

Rancher Labs公司产品  http://rancher.com/

Rancher Labs 公司目前有2个产品。

  • Rancher Docker容器管理平台
  • RancherOS 一种适合Docker运行的Linux发行版,类似于CoreOS

Rancher Docker容器管理平台

如果说原生的Docker是一个一个集装箱,Rancher可以比喻成集装箱船,平台化管控,带着应用航行。

rancher 承载 docker

rancher 承载 docker

 

Docker环境安装

以下是在CentOS7的环境下安装Rancher

Docker官方安装方式

curl -sSL https://get.docker.com/ | sh

在国内环境下利用DaoCloud加速安装Docker环境

curl -sSL https://get.daocloud.io/docker | sh
curl -sSL https://get.daocloud.io/daotools/set_mirror.sh | sh -s http://你的daocloudID.m.daocloud.io #设置国内镜像加速下载
systemctl start docker.service #CentOS7 启动docker
systemctl enable docker.service #CentOS7 开机自启动docker
docker version #查看docker版本
docker info #查看docker信息
sudo service docker status #查看docker状态

安装Rancher Management Server 管理端

docker run -d --restart=always -p 8080:8080 rancher/server

安装Rancher Agent 被控端

主控端IP:8080 http://192.168.33.11:8080/ > Add Host
复制第五步的内容到被控机安装

sudo docker run -e CATTLE_HOST_LABELS='center=localdev&host=dev'  -d --privileged -v /var/run/docker.sock:/var/run/docker.sock -v /var/lib/rancher:/var/lib/rancher rancher/agent:v1.0.2 http://192.168.33.11:8080/v1/scripts/31B86F01A71423902C9F:1474722000000:zRPBZeQo9rLTzrnTvhdfKRyBh3o

说明

安装好“Rancher Agent 被控端”后,就可以在 “Rancher Management Server 管理端” 管理、部署docker了
rancher没多少中文资料,直接看官方文档

扩展

Rancher支持&文档
Rancher 实战红宝书
DockerInfo Rancher
Docker编排工具调研:Rancher
都说要做细分,Rancher Labs想通过大而全的功能,帮助Docker完成在大型企业的落地
容器服务如何在企业客户落地?Rancher解决之道分享