存档

‘Docker容器技术’ 分类的存档

Docker与传统虚拟化的差别

2017年1月9日 评论已被关闭

Docker与传统虚拟化的差别
http://blog.csdn.net/u010022051/article/details/50952779
1. VM –> Dockers (职能更少)
原来由一个虚拟机变成现在多个Docker,每一个Docker里面所运行的服务智能会更少。
2. IP –> Ips (关系更加复杂)
一个IP变成多个IP,多个IP承载多个服务,整个应用之间的关系更加复杂,不像在原来有一个VM承载所有的服务 ,现在把所有的大的服务拆分为很多细小的微服务提供给用户,体现它的价值。
3. 服务节点增加
Docker扩容的机制很方便,服务节点会呈现一个明显上升的趋势,是一个曲线增长。
4. 生命周期更短
和传统的VM来比,Docker可能它的生命周期更短。

分类: Docker容器技术 标签:

docker无法用exec进入容器的问题[cannot allocate memory]

2016年12月4日 评论已被关闭

docker无法用exec进入容器的问题[cannot allocate memory]
http://xiaorui.cc/2015/06/11/docker无法用exec进入容器的问题cannot-allocate-memory/
今同事小飞飞遇到一个坑爹的问题,可乐死我了…. 我发现他们组docker用的量也不少,但是经常出问题…. 这次是无法使用docker -it exec 进入容器。奇怪的是docker的提示是 内存无法分配,我们ps aux看了下docker的后端进程,内存已经用到40G了… … 

[ruifengyun@wx-social-web01 socialx]$ docker exec -it wh-online-deploy bash
Cannot run exec command 7559431b2205817b2405d33cc22339dcf90f9e3a9f8c01b2f93e7562bcf1f279 in container c326f588d91bf77a3234ac0a063543e8b27d69f43934b486593f2a1c2dd33f61: fork/exec /usr/bin/docker: cannot allocate memory Error starting exec command in container

docker的版本是1.5

[ruifengyun@wx-social-web01 socialx]$ docker -v
Docker version 1.5.0, build a8a31ef/1.5.0

[ruifengyun@wx-social-web01 socialx]$ free -m

total used free shared buffers cached
Mem: 64375 48876 15499 0 505 9739
-/+ buffers/cache: 38631 25744
Swap: 0 0 0

看了下docker的github里的issue,大多数人把overcommit_memory配置成1或者2 .

[ruifengyun@wx-social-web01 socialx]$ cat /proc/sys/vm/overcommit_memory
0
[ruifengyun@wx-social-web01 socialx]$ cat /proc/sys/vm/overcommit_ratio
50

您还可以配置交换空间;在这种情况下,进程不会被杀死,但如果内存使用量增长太多,系统可能会变得反应迟钝。
这虽然在一定程度上保证不死,但是问题是docker为毛占用了40G的内存… 最后的解决方法是,万能重启….

关于 docker cannot allocate memory Error starting exec command in container 的继续探讨…..

7-13,有遇到这jb问题了….. 已经确定其中一个容器里面的应用有个模块有内存泄漏的问题,fix解决….

但是让人奇怪的是,从docker主机外面查看内存占用,不会看到具体的进程,只会看到docker进程占用了50g的内存….

分类: Docker容器技术 标签:

Swarm, Swarmkit 和 Swarm模式的比较

2016年11月3日 评论已被关闭

Swarm, Swarmkit 和 Swarm模式的比较

http://mt.sohu.com/20160818/n464799101.shtml

Docker 1.12 版最大的性能特点之一是Swarm 模式。Docker使容器编排1.6以上的版本可以使用Swarm。在Docker 1.12(RC) 版发布之前几周,Docker发布了Swarmkit作为编排分布式系统的开源项目。对于这三个项目,我有一些困惑。在本博客中,我试图围绕这三个软件组件之间的相似性和差异性进行解释。我还创建了一个示例应用,并使用这三种方法部署该应用,这样更易于比较。

Docker Swarm 模式与Swarm根本不同,都使用Swarm命名本身就令人费解,倘若Docker能够将其重命名为其他的名字就好了。更让人不解的是,Docker1.12 版本将继续支持本地Swarm功能,这样做是为了保持向后兼容性。

在本博客中,我使用术语“Swarm”来指代传统Swarm功能,“SwarmNext”指代加入在1.12版中的新Swarm模式,“Swarmkit”指代探索中的开源编排项目。

Swarm, SwarmNext 和 Swarmkit

下表比较了Swarm和SwarmNext

Swarm SwarmNext
与Docker Engine分离,可作为容器运行 整合到Docker 引擎中
需要Consul, etcd等外部KV存储 无需外部KV存储
服务模型不可用 服务模型可用。提供可扩展性、滚动更行、服务发现、负载均衡和路由网特性。
通信不安全 控制和数据层都是安全的
与machine和compose集成 截止到1.12版本发布时尚未与machine和compose集成,将在随后发布的版本中整合。

下表比较了Swarmkit和SwarmNext

Swarmkit SwarmNext
探究开源项目 Swarmkit在SwarmNext内部使用,并与Docker Engine集成
Swarmkit需要构建并独立运行 Docker 1.12 与SwarmNext集成
无服务发现、负载均衡和路由网 服务发现、负载均衡和路由网可用
使用swarmctl CLI 使用常规 Docker CLI

示例应用

下面是一个非常简单的应用,其中有一个方便可用的投票Web服务器,可以从客户端访问。客户端的请求将在可用的Web服务器之间进行负载均衡。此应用将在一个自定义的覆盖网络中创建。我们将用Swarm, SwarmNext 和Swarmkit对此应用进行部署。

先决条件

  • 我使用了docker-机器版0.8.0-rc1和Docker 引擎版11.12.0-rc3。
  • “smakam/myubuntu” 容器是在常规Ubumtu的基础上加上一些附加工具如curl等,用于说明负载均衡。

使用Swarm的部署

步骤摘要如下

  • 创建KV存储。在本例中,我使用了Concul。
  • 使用已经创建的KV存储创建Docker实例。在本例中,我使用Docker机创建了Dockersh实例。
  • 创建一个覆盖网络。
  • 创建多个实例的投票web服务器和单一实例的客户端。所有web服务器必须共享同一个网络别名,以便从客户端的请求可以得到web服务器之间的负载平衡。

▌创建KV存储

docker-machine create -d virtualbox mh-keystore

eval “$(docker-machine env mh-keystore)”

docker run -d \

-p “8500:8500” \

-h “consul” \

progrium/consul -server -bootstrap

▌创建2个指向KV 存储的Docker Swarm 实例

docker-machine create \

-d virtualbox \

–swarm –swarm-master \

–swarm-discovery=”consul://$(docker-machine ip mh-keystore):8500″ \

–engine-opt=”cluster-store=consul://$(docker-machine ip mh-keystore):8500″ \

–engine-opt=”cluster-advertise=eth1:2376″ \

mhs-demo0

docker-machine create -d virtualbox \

–swarm \

–swarm-discovery=”consul://$(docker-machine ip mh-keystore):8500″ \

–engine-opt=”cluster-store=consul://$(docker-machine ip mh-keystore):8500″ \

–engine-opt=”cluster-advertise=eth1:2376″ \

mhs-demo1

▌创建覆盖网络

eval $(docker-machine env –swarm mhs-demo0)

docker network create –driver overlay overlay1

▌创建服务

两个投票容器的实例使用同样的别名“投票”,以便它们可以作为单一的服务被访问。

docker run -d –name=vote1 –net=overlay1 –net-alias=vote instavote/vote

docker run -d –name=vote2 –net=overlay1 –net-alias=vote instavote/vote

docker run -ti –name client –net=overlay1 smakam/myubuntu:v4 bash

▌我们将客户端容器连接到投票Web服务器

root@abb7ec6c67fc:/# curl vote | grep “container ID”

Processed by container ID a9c05cd4ee15

root@abb7ec6c67fc:/# curl -i vote | grep “container ID”

Processed by container ID ce94f38fc958

从上面的输出中我们可以看到,向”投票”服务发出的ping命令在“投票1”和“投票2”之间进行负载均衡,它们各自拥有不同的容器 ID。

使用SwarmNext进行部署

步骤摘要如下

  • 使用Docker machine 1.12 RC3 Docker 图像创建2个Docker实例。启动一个节点作为主节点,另一个为工作节点。
  • 创建一个覆盖网络。
  • 在上面创建的覆盖网络中创建具有2个备份的投票web服务和具有1个备份的客户端服务。

▌创建2 个Docker 实例

docker-machine create -d virtualbox node1

docker-machine create -d virtualbox node2

▌设置节点1为主节点

docker swarm init –listen-addr 192.168.99.100:2377

节点1除作为主节点以外,也将作为工作节点。

▌设置节点2为工作节点

docker swarm join 192.168.99.100:2377

▌我们来看如何运行节点

$ docker node ls

ID HOSTNAME MEMBERSHIP STATUS AVAILABILITY MANAGER STATUS

b7jhf7zddv2w2evze1bz44ukx * node1 Accepted Ready Active Leader

ca4jgzcnyz70ry4h5enh701fv node2 Accepted Ready Active

▌创建覆盖网络

docker network create –driver overlay overlay1

▌创建服务

docker service create –replicas 1 –name client –network overlay1 smakam/myubuntu:v4 ping docker.com

docker service create –name vote –network overlay1 –replicas 2 -p 8080:80 instavote/vote

对于本实例而言,不需要暴露端口到主机,反正我已经使用了。使用Docker 1.12 的路由网功能,端口8080被暴露于“节点1”和“节点2”。

▌我们来看如何运行服务

$ docker service ls

ID NAME REPLICAS IMAGE COMMAND

2rm1svgfxzzw client 1/1 smakam/myubuntu:v4 ping docker.com

af6lg0cq66bl vote 2/2 instavote/vote

▌我们将客户端容器连接到投票Web服务器

# curl vote | grep “container ID”

Processed by container ID c831f88b217f

# curl vote | grep “container ID”

Processed by container ID fe4cc375291b

从上面的输出中,我们可以看到从客户端到2个服务器容器之间进行负载均衡。

使用Swarmkit进行部署

步骤如下

  • 创建Docker 机2节点集群。我能够创建Swarm集群并且不需要KV存储就能使用它。出于某种原因,没有KV存储,覆盖网络没有运行。所以对这个例子我不得不使用KV存储。
  • 创建Swarmkit并导出二进制文件到Swarm节点。
  • 创建具有2个节点的Swarm 集群。
  • 创建覆盖网络,并在这个覆盖网络中创建服务。

▌建立Swarmkit

这里Swarmkit是建立在GO 容器之中的。

git clone https://github.com/docker/swarmkit.git

eval $(docker-machine env swarm-01)

docker run -it –name swarmkitbuilder -v `pwd`/swarmkit:/go/src/github.com/docker/swarmkit golang:1.6 bash

cd /go/src/github.com/docker/swarmkit

make binaries

▌创建带KV存储的Docker 实例

docker-machine create \

-d virtualbox \

–engine-opt=”cluster-store=consul://$(docker-machine ip mh-keystore):8500″ \

–engine-opt=”cluster-advertise=eth1:2376″ \

swarm-01

docker-machine create -d virtualbox \

–engine-opt=”cluster-store=consul://$(docker-machine ip mh-keystore):8500″ \

–engine-opt=”cluster-advertise=eth1:2376″ \

swarm-02

▌导出Swarmkit二进制文本到节点

docker-machine scp bin/swarmd swarm-01:/tmp

docker-machine scp bin/swarmctl swarm-01:/tmp

docker-machine ssh swarm-01 sudo cp /tmp/swarmd /tmp/swarmctl /usr/local/bin/

docker-machine scp bin/swarmd swarm-02:/tmp

docker-machine scp bin/swarmctl swarm-02:/tmp

docker-machine ssh swarm-02 sudo cp /tmp/swarmd /tmp/swarmctl /usr/local/bin/

▌创建Swarm丛集

Master:

docker-machine ssh swarm-01

swarmd -d /tmp/swarm-01 \

–listen-control-api /tmp/swarm-01/swarm.sock \

–listen-remote-api 192.168.99.101:4242 \

–hostname swarm-01 &

Worker:

swarmd -d /tmp/swarm-02 \

–hostname swarm-02 \

–listen-remote-api 192.168.99.102:4242 \

–join-addr 192.168.99.101:4242 &

▌创建覆盖网络和服务

swarmctl network create –driver overlay –name overlay1

swarmctl service create –name vote –network overlay1 –replicas 2 –image instavote/vote

swarmctl service create –name client –network overlay1 –image smakam/myubuntu:v4 –command ping,docker.com

▌下列命令显示这2个节点丛集

export SWARM_SOCKET=/tmp/swarm-01/swarm.sock

swarmctl node ls

ID Name Membership Status Availability Manager Status

— —- ———- —— ———— ————–

5uh132h0acqebetsom1z1nntm swarm-01 ACCEPTED READY ACTIVE REACHABLE *

5z8z6gq36maryzrsy0cmk7f51 ACCEPTED UNKNOWN ACTIVE

▌下列命令显示从客户端到投票Web服务器的成功连接

# curl 10.0.0.3 | grep “container ID”

Processed by container ID 78a3e9b06b7f

# curl 10.0.0.4 | grep “container ID”

Processed by container ID 04e02b1731a0

在上面的输出中,因为服务器发现和负载均衡没有与Swarmkit集成,我们已经收到容器 IP地址发出的ping命令。

问题

我提出在Swarmkit覆盖网络中使用KV存储的需要的问题。这似乎是我的一个bug,又或许我丢失了一些选项。

总结

SwarmNext(Swarm 模式)是对原有Docker Swarm的巨大改善。在Docker中有服务对象将使缩放、滚动更新、服务发现、负载均衡和路由网等功能更容易实现,这也使得Swarm能够赶上Kubernetes之类的某些功能。Docker已经在1.12版中支持SwarmNext和Swarm,使得已经部署了Swarm的生产用户不会受到部分升级的影响。SwarmNext并不具有所有的功能,包括与Compose和存储插件的集成。不久这一点将被添加到SwarmNext。从长远看,我认为Swarm将会过时,而SwarmNext将会成为在Swarm中进行编排的唯一模式。Swarmkit作为一个开源项目,允许对Swarmkit进行独立开发,允许任何为分布应用开发编排系统的人将其作为一个独立模块进行使用。

本文作者Sreenivas Makam,由寄云科技翻译。欢迎关注寄云科技订阅号(neuclouddy),这里有最新云服务行业资讯,更有与PaaS、运维相关的技术干货!欢迎加入PaaS行业交流QQ群(421312857),关于PaaS的一切您都可以在这里与其他小伙伴共同探讨学习,小伙伴们等你哦~

分类: Docker容器技术 标签: ,

Docker基础技术:AUFS

2016年11月3日 评论已被关闭

Docker基础技术:AUFS

http://www.open-open.com/lib/view/open1440483391763.html

Docker基础技术:AUFS
AUFS是一种Union File System,所谓UnionFS就是把不同物理位置的目录合并mount到同一个目录中。UnionFS的一个最主要的应用是,把一张CD/DVD和一个硬盘目录给联合 mount在一起,然后,你就可以对这个只读的CD/DVD上的文件进行修改(当然,修改的文件存于硬盘上的目录里)。

AUFS又叫Another UnionFS,后来叫Alternative UnionFS,后来可能觉得不够霸气,叫成Advance UnionFS。是个叫Junjiro Okajima(岡島順治郎)在2006年开发的,AUFS完全重写了早期的UnionFS 1.x,其主要目的是为了可靠性和性能,并且引入了一些新的功能,比如可写分支的负载均衡。AUFS在使用上全兼容UnionFS,而且比之前的UnionFS在稳定性和性能上都要好很多,后来的UnionFS 2.x开始抄AUFS中的功能。但是他居然没有进到Linux主干里,就是因为Linus不让,基本上是因为代码量比较多,而且写得烂(相对于只有3000行的union mount和10000行的UnionFS,以及其它平均下来只有6000行代码左右的VFS,AUFS居然有30000行代码),所以,岡島不断地改进代码质量,不断地提交,不断地被Linus拒掉,所以,到今天AUFS都还进不了Linux主干(今天你可以看到AUFS的代码其实还好了,比起OpenSSL好N倍,要么就是Linus对代码的质量要求非常高,要么就是Linus就是不喜欢AUFS)。

不过,好在有很多发行版都用了AUFS,比如:Ubuntu 10.04,Debian6.0, Gentoo Live CD支持AUFS,所以,也OK了。

好了,扯完这些闲话,我们还是看一个示例吧(环境:Ubuntu 14.04)

首先,我们建上两个目录(水果和蔬菜),并在这两个目录中放上一些文件,水果中有苹果和蕃茄,蔬菜有胡萝卜和蕃茄。

$ tree
.
├── fruits
│   ├── apple
│   └── tomato
└── vegetables
    ├── carrots
    └── tomato

然后,我们输入以下命令:

# 创建一个mount目录
$ mkdir mnt

# 把水果目录和蔬菜目录union mount到 ./mnt目录中
$ sudo mount -t aufs -o dirs=./fruits:./vegetables none ./mnt

#  查看./mnt目录
$ tree ./mnt
./mnt
├── apple
├── carrots
└── tomato

我们可以看到在./mnt目录下有三个文件,苹果apple、胡萝卜carrots和蕃茄tomato。水果和蔬菜的目录被union到了./mnt目录下了。

我们来修改一下其中的文件内容:

$ echo mnt > ./mnt/apple
$ cat ./mnt/apple
mnt
$ cat ./fruits/apple
mnt

上面的示例,我们可以看到./mnt/apple的内容改了,./fruits/apple的内容也改了。

$ echo mnt_carrots > ./mnt/carrots
$ cat ./vegetables/carrots 

$ cat ./fruits/carrots
mnt_carrots

上面的示例,我们可以看到,我们修改了./mnt/carrots的文件内容,./vegetables/carrots并没有变化,反而是./fruits/carrots的目录中出现了carrots文件,其内容是我们在./mnt/carrots里的内容。

也就是说,我们在mount aufs命令中,我们没有指它vegetables和fruits的目录权限,默认上来说,命令行上第一个(最左边)的目录是可读可写的,后面的全都是只读的。(一般来说,最前面的目录应该是可写的,而后面的都应该是只读的)

所以,如果我们像下面这样指定权限来mount aufs,你就会发现有不一样的效果(记得先把上面./fruits/carrots的文件删除了):

$ sudo mount -t aufs -o dirs=./fruits=rw:./vegetables=rw none ./mnt

$ echo "mnt_carrots" > ./mnt/carrots 

$ cat ./vegetables/carrots
mnt_carrots

$ cat ./fruits/carrots
cat: ./fruits/carrots: No such file or directory

现在,在这情况下,如果我们要修改./mnt/tomato这个文件,那么究竟是哪个文件会被改写?

$ echo "mnt_tomato" > ./mnt/tomato 

$ cat ./fruits/tomato
mnt_tomato

$ cat ./vegetables/tomato
I am a vegetable

可见,如果有重复的文件名,在mount命令行上,越往前的就优先级越高。

你可以用这个例子做一些各种各样的试验,我这里主要是给大家一个感性认识,就不展开试验下去了。

那么,这种UnionFS有什么用?

历史上,有一个叫Knoppix的Linux发行版,其主要用于Linux演示、光盘教学、系统急救,以及商业产品的演示,不需要硬盘安装,直接把CD/DVD上的image运行在一个可写的存储设备上(比如一个U盘上),其实,也就是把CD/DVD这个文件系统和USB这个可写的系统给联合mount起来,这样你对CD/DVD上的image做的任何改动都会在被应用在U盘上,于是乎,你可以对CD/DVD上的内容进行任意的修改,因为改动都在U盘上,所以你改不坏原来的东西。

我们可以再发挥一下想像力,你也可以把一个目录,比如你的源代码,作为一个只读的template,和另一个你的working directory给union在一起,然后你就可以做各种修改而不用害怕会把源代码改坏了。有点像一个ad hoc snapshot。

Docker把UnionFS的想像力发挥到了容器的镜像。你是否还记得我在介绍Linux Namespace上篇中用mount namespace和chroot山寨了一镜像。现在当你看过了这个UnionFS的技术后,你是不是就明白了,你完全可以用UnionFS这样的技术做出分层的镜像来。

下图来自Docker的官方文档Layer,其很好的展示了Docker用UnionFS搭建的分层镜像。

Docker基础技术:AUFS

关于docker的分层镜像,除了aufs,docker还支持btrfs, devicemapper和vfs,你可以使用 -s 或 –storage-driver= 选项来指定相关的镜像存储。在Ubuntu 14.04下,docker默认Ubuntu的 aufs(在CentOS7下,用的是devicemapper,关于devicemapper,我会以以后的文章中讲解)你可以在下面的目录中查看相关的每个层的镜像:

/var/lib/docker/aufs/diff/<id>

在docker执行起来后(比如:docker run -it ubuntu /bin/bash ),你可以从/sys/fs/aufs/si_[id]目录下查看aufs的mount的情况,下面是个示例:

#ls /sys/fs/aufs/si_b71b209f85ff8e75/
br0      br2      br4      br6      brid1    brid3    brid5    xi_path
br1      br3      br5      brid0    brid2    brid4    brid6 

# cat /sys/fs/aufs/si_b71b209f85ff8e75/*
/var/lib/docker/aufs/diff/87315f1367e5703f599168d1e17528a0500bd2e2df7d2fe2aaf9595f3697dbd7=rw
/var/lib/docker/aufs/diff/87315f1367e5703f599168d1e17528a0500bd2e2df7d2fe2aaf9595f3697dbd7-init=ro+wh
/var/lib/docker/aufs/diff/d0955f21bf24f5bfffd32d2d0bb669d0564701c271bc3dfc64cfc5adfdec2d07=ro+wh
/var/lib/docker/aufs/diff/9fec74352904baf5ab5237caa39a84b0af5c593dc7cc08839e2ba65193024507=ro+wh
/var/lib/docker/aufs/diff/a1a958a248181c9aa6413848cd67646e5afb9797f1a3da5995c7a636f050f537=ro+wh
/var/lib/docker/aufs/diff/f3c84ac3a0533f691c9fea4cc2ceaaf43baec22bf8d6a479e069f6d814be9b86=ro+wh
/var/lib/docker/aufs/diff/511136ea3c5a64f264b78b5433614aec563103b4d4702f3ba7d4d2698e22c158=ro+wh
64
65
66
67
68
69
70
/run/shm/aufs.xino

你会看到只有最顶上的层(branch)是rw权限,其它的都是ro+wh权限只读的。

关于docker的aufs的配置,你可以在/var/lib/docker/repositories-aufs这个文件中看到。

AUFS的一些特性

AUFS有所有Union FS的特性,把多个目录,合并成同一个目录,并可以为每个需要合并的目录指定相应的权限,实时的添加、删除、修改已经被mount好的目录。而且,他还能在多个可写的branch/dir间进行负载均衡。

上面的例子,我们已经看到AUFS的mount的示例了。下面我们来看一看被union的目录(分支)的相关权限:

  • rw表示可写可读read-write。
  • ro表示read-only,如果你不指权限,那么除了第一个外ro是默认值,对于ro分支,其永远不会收到写操作,也不会收到查找whiteout的操作。
  • rr表示real-read-only,与read-only不同的是,rr标记的是天生就是只读的分支,这样,AUFS可以提高性能,比如不再设置inotify来检查文件变动通知。

权限中,我们看到了一个术语:whiteout,下面我来解释一下这个术语。

一般来说ro的分支都会有wh的属性,比如 “[dir]=ro+wh”。所谓whiteout的意思,如果在union中删除的某个文件,实际上是位于一个readonly的分支(目录)上,那么,在mount的union这个目录中你将看不到这个文件,但是read-only这个层上我们无法做任何的修改,所以,我们就需要对这个readonly目录里的文件作whiteout。AUFS的whiteout的实现是通过在上层的可写的目录下建立对应的whiteout隐藏文件来实现的。

看个例子:

假设我们有三个目录和文件如下所示(test是个空目录):

# tree
.
├── fruits
│   ├── apple
│   └── tomato
├── test
└── vegetables
    ├── carrots
    └── tomato

我们如下mount:

# mkdir mnt

# mount -t aufs -o dirs=./test=rw:./fruits=ro:./vegetables=ro none ./mnt

# # ls ./mnt/
apple  carrots  tomato

现在我们在权限为rw的test目录下建个whiteout的隐藏文件.wh.apple,你就会发现./mnt/apple这个文件就消失了:

 # touch ./test/.wh.apple

# ls ./mnt
carrots  tomato

上面这个操作和 rm ./mnt/apple是一样的。

相关术语

šBranch – 就是各个要被union起来的目录(就是我在上面使用的dirs的命令行参数)

  • šBranch根据被union的顺序形成一个stack,一般来说最上面的是可写的,下面的都是只读的。
  • šBranch的stack可以在被mount后进行修改,比如:修改顺序,加入新的branch,或是删除其中的branch,或是直接修改branch的权限

šWhiteoutOpaque

  • š如果UnionFS中的某个目录被删除了,那么就应该不可见了,就算是在底层的branch中还有这个目录,那也应该不可见了。
  • šWhiteout就是某个上层目录覆盖了下层的相同名字的目录。用于隐藏低层分支的文件,也用于阻止readdir进入低层分支。
  • šOpaque的意思就是不允许任何下层的某个目录显示出来。
  • š在隐藏低层档的情况下,whiteout的名字是’.wh.<filename>’。
  • š在阻止readdir的情况下,名字是’.wh..wh..opq’或者 ’.wh.__dir_opaque’。
相关问题

看到上面这些,你一定会有几个问题:

其一、你可能会问,要有文件在原来的地方被修改了会怎么样?mount的目录会一起改变吗?答案是会的,也可以是不会的。因为你可以指定一个叫udba的参数(全称:User’s Direct Branch Access),这个参数有三个取值:

  • udba=none – 设置上这个参数后,AUFS会运转的更快,因为那些不在mount目录里发生的修改,aufs不会同步过来了,所以会有数据出错的问题。
  • udba=reval – 设置上这个参数后,AUFS会去查文件有没有被更新,如果有的话,就会把修改拉到mount目录内。
  • udba=notify – 这个参数会让AUFS为所有的branch注册inotify,这样可以让AUFS在更新文件修改的性能更高一些。

其二、如果有多个rw的branch(目录)被union起来了,那么,当我创建文件的时候,aufs会创建在哪里呢? aufs提供了一个叫create的参数可以供你来配置相当的创建策略,下面有几个例子。

create=rr | round−robin 轮询。下面的示例可以看到,新创建的文件轮流写到三个目录中

hchen$ sudo mount -t aufs  -o dirs=./1=rw:./2=rw:./3=rw -o create=rr none ./mnt
hchen$ touch ./mnt/a ./mnt/b ./mnt/c
hchen$ tree
.
├── 1
│   └── a
├── 2
│   └── c
└── 3
    └── b

create=mfs[:second] | most−free−space[:second] 选一个可用空间最好的分支。可以指定一个检查可用磁盘空间的时间。

create=mfsrr:low[:second] 选一个空间大于low的branch,如果空间小于low了,那么aufs会使用 round-robin 方式。

更多的关于AUFS的细节使用参数,大家可以直接在Ubuntu 14.04下通过 man aufs 来看一下其中的各种参数和命令。

AUFS的性能

AUFS的性能慢吗?也慢也不慢。因为AUFS会把所有的分支mount起来,所以,在查找文件上是比较慢了。因为它要遍历所有的branch。是个O(n)的算法(很明显,这个算法有很大的改进空间的)所以,branch越多,查找文件的性能也就越慢。但是,一旦AUFS找到了这个文件的inode,那后以后的读写和操作原文件基本上是一样的。

所以,如果你的程序跑在在AUFS下,open和stat操作会有明显的性能下降,branch越多,性能越差,但是在write/read操作上,性能没有什么变化。

IBM的研究中心对Docker的性能给了一份非常不错的性能报告(PDF)《An Updated Performance Comparison of Virtual Machinesand Linux Containers

我截了两张图出来,第一张是顺序读写,第二张是随机读写。基本没有什么性能损失的问题。而KVM在随机读写的情况也就有点慢了(但是,如果硬盘是SSD的呢?)

Docker基础技术:AUFS

 

顺序读写

Docker基础技术:AUFS

 

随机读写

延伸阅读

(全文完)

分类: Docker容器技术 标签:

Docker Toolbox常见错误解决方案

2016年11月2日 评论已被关闭

Docker Toolbox常见错误解决方案
http://blog.csdn.net/gezhonglei2007/article/details/51541580
原文:https://docs.docker.com/faqs/troubleshoot/

错误1
Error checking TLS connection: Error checking and/or regenerating the certs: There was an error validating certificates for host “192.168.99.100:2376”: dial tcp 192.168.99.100:2376: i/o timeout
错误2
Error checking TLS connection: Error checking and/or regenerating the certs: There was an error validating certificates for host “192.168.99.100:2376”: x509: certificate is valid for 192.168.99.101, not 192.168.99.100
You can attempt to regenerate them using ‘docker-machine regenerate-certs [name]’.
Be advised that this will trigger a Docker daemon restart which will stop running containers.
错误3
Unable to find image ‘hello-world:latest’ locally
Pulling repository docker.io/library/hello-world
Network timed out while trying to connect to https://index.docker.io/v1/repositories/library/hello-world/images. You may want to check your internet connection or if you are behind a proxy.
这些错误可能是由一些常用指令导致,像获取default主机的环境变量Docker-machine env default连接主机获取环境变量,
或者拉取镜像运行容器的指令docker run hello-world。

问题出现突然,而且不稳定。以下介绍几种通用的解决方案。(以下以default主机为例)

重新生成证书

$ docker-machine regenerate-certs default
Regenerate TLS machine certs? Warning: this is irreversible. (y/n): y
Regenerating TLS certificates
重启Docker主机

docker-machine restart default
将Docker Client连接的默认主机default

# 设置环境变量: 将default主机作为docker deamon(服务端)
eval $(docker-machine env default)
# 查看主机列表:default主机Active状态为’*’
docker-machine ls
关闭、移除、新建主机

# 关闭default主机
docker-machine stop default
# 移除default主机
docker-machine rm default
# 新建主机
docker-machine create –driver virtualbox default
使用HTTP代理出现的连接错误

通常在VPN网络环境中使用HTTP proxy时,用Docker Toolbox连接服务端会出错。

$ docker run hello-world
An error occurred trying to connect: Post https://192.168.99.100:2376/v1.20/containers/create: Forbidden

$ docker run ubuntu echo “hi”
An error occurred trying to connect: Post https://192.168.99.100:2376/v1.20/containers/create: Forbidden
在虚拟主机中配置代理设置

进入主机

# 进入default主机
docker-machine ssh default
编辑配置文件

# 编辑配置文件:/var/lib/boot2docker/profile
docker@default:~$ sudo vi /var/lib/boot2docker/profile
在配置文件最后添加NO_PROXY配置,配置文件内容如下:

# replace with your office’s proxy environment
export “HTTP_PROXY=http://PROXY:PORT”
export “HTTPS_PROXY=http://PROXY:PORT”
# you can add more no_proxy with your environment.
export “NO_PROXY=192.168.99.*,*.local,169.254/16,*.example.com,192.168.59.*”
重启主机

docker@default:~$ sudo /etc/init.d/docker restart
docker@default:~$ exit
创建虚拟机时直接指定配置

可删除虚拟机重建

docker-machine create -d virtualbox \
–engine-env HTTP_PROXY=http://example.com:8080 \
–engine-env HTTPS_PROXY=https://example.com:8080 \
–engine-env NO_PROXY=example2.com \
default

分类: Docker容器技术 标签: ,

容器集群管理平台的比较

2016年10月31日 评论已被关闭

容器集群管理平台的比较

https://my.oschina.net/taogang/blog/778136

摘要: 本文简单介绍了主流的容器管理平台包括Swarm,Kubernetes,Mesos,AWS ECS,并对它们做了基本的比较。

容器化和微服务是当前最热话题,不久之前,笔者(据说因为现在都不用笔了,“笔者”的称谓已经不合适了,因为输入用键盘,叫“键人”更为合适)参加QCon上海一个微服务监控的Session,场面爆棚,我不得不在拥挤的过道听完了整个session。随着要管理的容器越来越多,容器的集群管理平台成为了刚需!

Docker Swarm

Swarm是Docker公司在2014年12月初新发布的容器集群管理工具。它可以把多个主机变成一个虚拟的Docker主机来管理。Swarm使用Go语言开发,并且开源,在github上可以找到它的全部source code。Swarm使用标准的Docker API,给Docker用户带来无缝的集群使用体验。2016年7月, Swarm已经被整合进入Docker Engine。

功能

Docker Swarm提供API 和CLI来在管理运行Docker的集群,它的功能和使用本地的Docker并没有本质的区别。但是可以通过增加Node带来和好的扩展性。理论上,你可以通过增加节点(Node)的方式拥有一个无限大的Docker主机。

Swarm并不提供UI,需要UI的话,可以安装UCP,不过很不幸,这个UCP是收费的。

架构

Swarm的架构并不复杂,可以说非常简单。Manager负责容器的调度,Node负责容器的运行,Node运行Docker Daemon和Manager之间通过HTTP来通信。Docker Client通过Manager上暴露的标准Docker API来使用Docker的功能。

Swarm的集群协调和业务发现可以支持不同的第三方组件,包括:

  • Consul
  • Etcd
  • ZooKeeper
  • Docker Hub

如果对集群协调的概念不熟悉,可以参考我的另一篇博客《使用Python进行分布式系统协调 (ZooKeeper,Consul, etcd )》

Swarm的基本容器调度策略有三种:

  • spread  容器尽可能分布在不同的节点上
  • binpack 容器尽可能分布在同一个节点上
  • random 容器分布在随机的节点上

Swarm集群的高可用配置很容易,以下图为例:

manager配置在不同的AWS AZ中,通过领导选举选出Primary manager。

多个节点分布在不同的AZ中,同时Consul/etcd/ZooKeeper也需要配成冗余的。

特点

Docker Swarm的特点是配置和架构都很简单,使用Docker原生的API,可以很好的融合Docker的生态系统。

 

Kubernetes

Kubernetes是Google开发的一套开源的容器应用管理系统,用于管理应用的部署,维护和扩张。利用Kubernetes能方便地管理跨机器运行容器化的应用。Kubernetes也是用Go语言开发的,在github上可以找到源代码。

Kubernetes 源于谷歌公司的内部容器管理系统Borg,经过了多年的生产环境的历炼,所以功能非常强大。

功能

Kubernetes主要提供一下的功能:

  • 使用Docker对应用程序包装(package)、实例化(instantiate)、运行(run)。
  • 以集群的方式运行、管理跨机器的容器。
  • 解决Docker跨机器容器之间的通讯问题。
  • Kubernetes的自我修复机制使得容器集群总是运行在用户期望的状态。
  • 应用的高可用和靠扩展
  • 支持应用的在线升级(Rolling Update)
  • 支持跨云平台(IaaS)的部署

为了支持这些功能,Kubernetes做了做了很多的抽象概念,所以,刚开始使用Kubernetes,需要学习不少的新概念,包括:

  • Pod
    Pod是Kubernetes的基本操作单元,把相关的一个或多个容器构成一个Pod,通常Pod里的容器运行相同的应用,或者是相关的应用。Pod包含的容器运行在同一个Minion(Host)上,看作一个统一管理单元,共享相同的volumes和network namespace/IP和Port空间。
  • Job
    Job是一个生命周期比较短的应用,一般只会在出错的情况下重启,可以通过配置Job的并发和运行次数来扩展Job
  • Service
    Service是一个生命周期比较长的应用,会在任何退出时重启,可以通过配置Service的复制(Replica)来达到高扩展和高可用
  • Recplica Controller
    Replication Controller确保任何时候Kubernetes集群中有指定数量的pod副本(replicas)在运行, 如果少于指定数量的pod副本(replicas),Replication Controller会启动新的Container,反之会杀死多余的以保证数量不变。Replication Controller使用预先定义的pod模板创建pods,一旦创建成功,pod 模板和创建的pods没有任何关联,可以修改pod 模板而不会对已创建pods有任何影响,也可以直接更新通过Replication Controller创建的pods

以上是一些核心概念,除了这些,Kubernetes还提供其它一些概念,来支持应用程序的运维,包括:

  • Label
    对系统中的对象通过Label的方式来管理
  • Namespace
    对对象,资源分组,可以用于支持多租户
  • Config Map
    提供全局的配置数据存储

总之,功能强大,系统概念繁多,比较复杂。

Kubernetes支持安装UI的addon,来管理整个系统:

架构

下图是Kubernetes的基本架构:

  • Master
    Master定义了Kubernetes 集群Master/API Server的主要声明,Client(Kubectl)调用Kubernetes API,管理Kubernetes主要构件Pods、Services、Minions、容器的入口。Master由API Server、Scheduler以及Registry等组成。
    Scheduler收集和分析当前Kubernetes集群中所有Minion节点的资源(内存、CPU)负载情况,然后依此分发新建的Pod到Kubernetes集群中可用的节点。由于一旦Minion节点的资源被分配给Pod,那这些资源就不能再分配给其他Pod, 除非这些Pod被删除或者退出, 因此,Kubernetes需要分析集群中所有Minion的资源使用情况,保证分发的工作负载不会超出当前该Minion节点的可用资源范围
  • Minion
    Minion负责运行Pod,Service,Jobs, Minion通过Kubelet和Master通信。Proxy解决了外部网络能够访问跨机器集群中容器提供的应用服务。
  • etcd
    负责集群的协调和服务发现

特点

Kubernetes提供了很多应用级别的管理能力,包括高可用可高扩展,当然为了支持这些功能,它的架构和概念都比较复杂,当然我觉得为了获得这些功能,值!

 

Apache Mesos

Mesos是为软件定义数据中心而生的操作系统,跨数据中心的资源在这个系统中被统一管理。Mesos的初衷并非管理容器,只是随着容器的发展,Mesos加入了容器的功能。Mesos可以把不同机器的计算资源统一管理,就像同一个操作系统,用于运行分布式应用程序。

Mesos的起源于Google的数据中心资源管理系统Borg。你可以从WIRED杂志的这篇文章中了解更多关于Borg起源的信息及它对Mesos影响。

功能

Mesos的主要功能包括:

  • 高度的可扩展和高可用
  • 可自定义的两级调度
  • 提供API进行应用的扩展
  • 跨平台

下图是Mesos的管理界面:

架构

Mesos的基本架构如下

 

  • Master
    Master负责资源的统一协调和Slave的管理。 Master协调全部的Slave,并确定每个节点的可用资源,聚合计算跨节点的所有可用资源的报告,然后向注册到Master的Framework(作为Master的客户端)发出资源邀约。Mesos实现了两级调度架构,它可以管理多种类型的应用程序。第一级调度是Master的守护进程,管理Mesos集群中所有节点上运行的Slave守护进程。集群由物理服务器或虚拟服务器组成,用于运行应用程序的任务,比如Hadoop和MPI作业。第二级调度由被称作Framework的“组件”组成。
  • Slave
    Salve运行执行器(Executor)进程来运行任务。
  • Framework
    Framework包括调度器(Scheduler)和执行器(Executor)进程,其中每个节点上都会运行执行器。Mesos能和不同类型的Framework通信,每种Framework由相应的应用集群管理。
    Framework可以根据应用程序的需求,选择接受或拒绝来自master的资源邀约。一旦接受邀约,Master即协调Framework和Slave,调度参与节点上任务,并在容器中执行,以使多种类型的任务
  • ZooKeeper
    Zookeeper负责集群的协调,Master的领导选举等

特点

Mesos相比Kubernetes和Swarm更为成熟,但是Mesos主要要解决的是操作系统级别的抽象,并非为了容器专门设计,如果用户出了容器之外,还要集成其它的应用,例如Hadoop,Spark,Kafka等,Mesos更为合适。Mesos是一个更重量级的集群管理平台,功能更丰富,当然很多功能要基于各种Framework。
Mesos的扩展性非常好,最大支持50000节点,如果对扩展性要求非常高的话么,Mesos是最佳选择。

 

AWS ECS

ECS (Amazon EC2 Container Service )是亚马逊开发出的高度可扩展的高性能容器集群服务。在托管的 Amazon EC2 实例集群上轻松运行容器应用和服务。他最大的好处就是在云上,不需要自己管理数据中心的机器和网络。

功能

ECS继承了AWS服务的高扩展和高可用性,安全也可以得到保证。

在基本容器管理的基础上,ECS使用TaskService的概念来管理应用。

Task类似Docker Compose,使用一个JSON描述要运行的应用。Service是更高一层的抽象,包含多个task的运行实例,通过修改task实例的数量,可以控制服务的伸缩。同时Service可以保证指定数量的Task在运行,当出现错误的时候,重启失败的Task

架构

下图是ECS的架构图:

使用EC2,ELB,安全组等大家熟悉的AWS的概念,AWS用户可以轻松管理你的容器集群。并且不需要付初基本资源以外的费用。

通过ECS agent可以是Container连接到ECS集群。ECS Agent使用Go开发,已开源。

我们并不清楚ECS的调度策略,但是AWS提供了一个例子,如果继承第三方的调度策略。

通过Cloud Watch Log,我们可以很方便的对整个集群进行监控。

特点

如果你是一个AWS的重度用户,ECS是个不错的选择,因为你可以是把你的容器集群运行在AWS的云上,管理起来非常方便。

 

比较

这里对几个平台做一个简单的比较:

 Swarm Kubernetes Mesos ECS
基本功能 Docker原生的集群管理工具 开源的容器集群工具,提供应用级别的部署,维护和扩张功能 基于数据中心的操作系统 基于云的高可用,高扩展容器集群
高层次抽象 Pod
Job
Service
Task
Service
应用扩展性 支持 Framework 支持 支持
应用高可用性 支持 Framework 支持 支持
集群协调和服务发现 etcd
ZooKeeper
Consul
etcd ZooKeeper
调度策略(Schedule) 内置,可扩展 内置 两级别,可扩展 可扩展
监控 Logging Driver Heapter,ELK Addon 内置 CloudWatch
用户界面 CLI
API
UCP UI
CLI
API
UI
API
UI
CLI
API
AWS Console
开发语言 Go Go Java NA
开源
最大支持管理节点数 官方1000
非官方5000
官方1000
非官方2000
10000

总结

四个平台,Swarm是最轻量级的,功能也最简单,适于有大量Docker实例环境的用户。Kubernetes增加了很多应用级别的功能,适用于快速应用的部署和维护。Mesos最重,适用于已经有了相当的应用和容器混合的环境。ECS则推荐给AWS的用户或者不希望自己管理数据中心的云用户。

 

相关链接

分类: Docker容器技术 标签:

jenkins 集成 docker tomcat 自动化测试脚本

2016年10月31日 评论已被关闭

jenkins 集成 docker tomcat 自动化测试脚本

https://segmentfault.com/a/1190000004297705

最近在搞jenkins + docker CI,把自己写的集成脚本分享出来给大家。里面很多路径或者名称是我自己的,自行替换掉。

#!/bin/sh
# Jenkins Build Shell Script
# Author zdzhou@iflytek.com

set -e 
# Get running docker image name
cid=`docker ps | grep 'isearch' | awk {'print $1'}`
echo $cid

# If exists running isearch docker image, stop and remove it
if [ -n "$cid" ]
then
    echo Get the running docker container id of isearch: $cid
    docker stop $cid
    docker rm $cid
else  
    echo There is no running isearch docker container
fi

# Copy target war to dest directory
cd ${JENKINS_HOME}/workspace/${JOB_NAME}/itv-web/
echo Current work directory `pwd`
cp target/itv-web.war /usr/local/tomcat/webapps
echo Run docker image
docker run -d -p 8080:8080 -v /usr/local/isearch:/usr/local/isearch -v /usr/local/tomcat/webapps:/usr/local/tomcat/webapps --name=isearch${SVN_REVISION} isearch

# Wait for starting docker container
totalWait=0
until [ "`/usr/bin/docker inspect -f {{.State.Running}} isearch${SVN_REVISION}`" == "true" ] 
do
   totalWait=$[ $totalWait + 2 ]
   if (( $totalWait > 10 ))
   then
      echo "Start docker container timeout"
      exit 1
   fi
   echo "Waiting for starting docker container: $totalWait minute" 
   sleep 2m
done
echo "Start docker container success "

# Wait for starting tomcat
totalWait=0
until [ "`curl -o /dev/null --silent -m 10 --retry 1 --connect-timeout 10 --head --write-out '%{http_code}\n' http://127.0.0.1:8080/itv-web/v3/videosearch/?appid=aginomoto`" = "200" ]
do 
  totalWait=$[ $totalWait + 3 ]
  if (($totalWait > 36 ))
  then 
    echo "Start tomcat timeout"
    exit 1
  fi
  echo "Wait for starting tomcat: "$totalWait" minute"
  sleep 3m
done 
echo "Start tomcat service success"

# Run automatic function test script
echo "Start automatic function test"
export LOG_HOME=${WORKSPACE}/test.log.d/${BUILD_NUMBER}
cd /data/jenkins_home/test.framework.d
exec ./automatic_test.sh 

原文链接http://segmentfault.com/a/1190000004297705

分类: Docker容器技术 标签:

Docker exec与Docker attach

2016年10月30日 评论已被关闭

Docker exec与Docker attach

http://blog.csdn.net/halcyonbaby/article/details/46884605

Docker exec与Docker attach

不论是开发者是运维人员,都经常有需要进入容器的诉求。
目前看,主要的方法不外乎以下几种:
1. 使用ssh登陆进容器
2. 使用nsenter、nsinit等第三方工具
3. 使用docker本身提供的工具

方法1需要在容器中启动sshd,存在开销和攻击面增大的问题。同时也违反了Docker所倡导
的一个容器一个进程的原则。
方法2需要额外学习使用第三方工具。
所以大多数情况最好还是使用Docker原生方法,Docker目前主要提供了Docker exec和
Docker attach两个命令。

以下在fedora21,docker1.7上验证。

Docker attach

Docker attach可以attach到一个已经运行的容器的stdin,然后进行命令执行的动作。
但是需要注意的是,如果从这个stdin中exit,会导致容器的停止。


[root@localhost temp]# docker ps
CONTAINER ID        IMAGE                       COMMAND             CREATED              STATUS              PORTS               NAMES
2327e7eab0ed        busybox:buildroot-2014.02   "/bin/sh"           About a minute ago   Up About a minute                       bb2
[root@localhost temp]# docker attach bb2
/ # ls
bin      dev      etc      home     lib      lib64    linuxrc  media    mnt      opt      proc     root     run      sbin     sys      tmp      usr      var
/ # pwd
/
/ #

Docker exec

关于-i、-t参数

可以看出只用-i时,由于没有分配伪终端,看起来像pipe执行一样。但是执行结果、命令
返回值都可以正确获取。


[root@localhost temp]# docker exec -i bb2 /bin/sh
date
Tue Jul 14 04:01:11 UTC 2015
echo $?
0
dir
/bin/sh: dir: not found
echo $?
127

使用-it时,则和我们平常操作console界面类似。而且也不会像attach方式因为退出,导致
整个容器退出。
这种方式可以替代ssh或者nsenter、nsinit方式,在容器内进行操作。


[root@localhost temp]# docker exec -it bb2 /bin/sh
/ # pwd
/
/ # echo $?
0
/ # dir
/bin/sh: dir: not found
/ # echo $?
127

如果只使用-t参数,则可以看到一个console窗口,但是执行命令会发现由于没有获得stdin
的输出,无法看到命令执行情况。


[root@localhost temp]# docker exec -t bb2 /bin/sh
/ # pwd

hanging....
[root@localhost temp]# docker exec -t bb2 pwd
/
[root@localhost temp]# echo $?
0
[root@localhost temp]# docker exec -t bb2 dir
2015/07/14 04:03:57 docker-exec: failed to exec: exec: "dir": executable file not found in $PATH
[root@localhost temp]# echo $?
0

docker exec执行后,会命令执行返回值。(备注Docker1.3似乎有Bug,不能正确返回命令执行结果)


[root@localhost temp]# docker exec -it bb cat /a.sh
echo "running a.sh"
exit 10
[root@localhost temp]# docker exec -t bb /a.sh
running a.sh
[root@localhost temp]# echo $?
10
[root@localhost temp]# docker exec -it bb /a.sh
running a.sh
[root@localhost temp]# echo $?
10
[root@localhost temp]# docker exec -i bb /a.sh
running a.sh
[root@localhost temp]# echo $?
10
关于-d参数

在后台执行一个进程。可以看出,如果一个命令需要长时间进程,使用-d参数会很快返回。
程序在后台运行。


[root@localhost temp]# docker exec -d bb2 /a.sh
[root@localhost temp]# echo $?
0

如果不使用-d参数,由于命令需要长时间执行,docker exec会卡住,一直等命令执行完成
才返回。


[root@localhost temp]# docker exec  bb2 /a.sh
^C[root@localhost temp]#
[root@localhost temp]#
[root@localhost temp]# docker exec -it  bb2 /a.sh
^C[root@localhost temp]#
[root@localhost temp]# docker exec -i  bb2 /a.sh
^C[root@localhost temp]# docker exec -t  bb2 /a.sh
^C[root@localhost temp]#

Docker学习笔记 — 开启Docker远程访问

2016年10月29日 评论已被关闭

Docker学习笔记 — 开启Docker远程访问

http://blog.csdn.net/wangtaoking1/article/details/44494847

默认情况下,Docker守护进程会生成一个socket(/var/run/docker.sock)文件来进行本地进程通信,而不会监听任何端口,因此只能在本地使用docker客户端或者使用Docker API进行操作。
如果想在其他主机上操作Docker主机,就需要让Docker守护进程监听一个端口,这样才能实现远程通信。

修改Docker服务启动配置文件,添加一个未被占用的端口号,重启docker守护进程。

# vim /etc/default/docker
DOCKER_OPTS="-H 0.0.0.0:5555"
# service docker restart

此时发现docker守护进程已经在监听5555端口,在另一台主机上可以通过该端口访问Docker进程了。

# docker -H IP:5555 images

但是我们却发现在本地操作docker却出现问题。

# docker images
FATA[0000] Cannot connect to the Docker daemon. Is 'docker -d' running on this host?

这是因为Docker进程只开启了远程访问,本地套接字访问未开启。我们修改/etc/default/docker,然后重启即可。

# vim /etc/default/docker
DOCKER_OPTS="-H unix:///var/run/docker.sock -H 0.0.0.0:5555"
# service docker restart

现在本地和远程均可访问docker进程了。


参考文档
1. http://longgeek.com/2014/09/14/remote-call-docker-api/

分类: Docker容器技术 标签:

linux 基于docker部署etcd集群

2016年10月28日 评论已被关闭

linux 基于docker部署etcd集群

本文前提条件是你在每台使用机器中已经装好了docker环境

机器环境变量设置

每台机器设置以下环境变量

export ETCD_VERSION=v3.1.0-alpha.1
export TOKEN=my-etcd-token
export CLUSTER_STATE=new
export NAME_1=etcd-node-0
export NAME_2=etcd-node-1
export NAME_3=etcd-node-2
export HOST_1=192.168.56.101
export HOST_2=192.168.56.104
export HOST_3=192.168.56.105
export CLUSTER=${NAME_1}=http://${HOST_1}:2380,${NAME_2}=http://${HOST_2}:2380,${NAME_3}=http://${HOST_3}:2380

每个机器安装etcd容器

进入HOST_1机器,设置环境变量和起容器。

export THIS_NAME=${NAME_1}
export THIS_IP=${HOST_1}

sudo docker run -d --net=host --name etcd quay.io/coreos/etcd:${ETCD_VERSION} \
    /usr/local/bin/etcd \
    --data-dir=data.etcd --name ${THIS_NAME} \
    --initial-advertise-peer-urls http://${THIS_IP}:2380 --listen-peer-urls http://${THIS_IP}:2380 \
    --advertise-client-urls http://${THIS_IP}:2379 --listen-client-urls http://${THIS_IP}:2379 \
    --initial-cluster ${CLUSTER} \
    --initial-cluster-state ${CLUSTER_STATE} --initial-cluster-token ${TOKEN}

进入HOST_2机器,设置环境变量和起容器

export THIS_NAME=${NAME_2}
export THIS_IP=${HOST_2}
sudo docker run --net=host -d --name etcd quay.io/coreos/etcd:${ETCD_VERSION} \
    /usr/local/bin/etcd \
    --data-dir=data.etcd --name ${THIS_NAME} \
    --initial-advertise-peer-urls http://${THIS_IP}:2380 --listen-peer-urls http://${THIS_IP}:2380 \
    --advertise-client-urls http://${THIS_IP}:2379 --listen-client-urls http://${THIS_IP}:2379 \
    --initial-cluster ${CLUSTER} \
    --initial-cluster-state ${CLUSTER_STATE} --initial-cluster-token ${TOKEN}

进入HOST_3机器,设置环境变量和起容器

export THIS_NAME=${NAME_3}
export THIS_IP=${HOST_3}
sudo docker run --net=host -d --name etcd quay.io/coreos/etcd:${ETCD_VERSION} \
    /usr/local/bin/etcd \
    --data-dir=data.etcd --name ${THIS_NAME} \
    --initial-advertise-peer-urls http://${THIS_IP}:2380 --listen-peer-urls http://${THIS_IP}:2380 \
    --advertise-client-urls http://${THIS_IP}:2379 --listen-client-urls http://${THIS_IP}:2379 \
    --initial-cluster ${CLUSTER} \
    --initial-cluster-state ${CLUSTER_STATE} --initial-cluster-token ${TOKEN}

测试集群运行情况:

docker exec etcd /bin/sh -c "export ETCDCTL_API=3 && /usr/local/bin/etcdctl put foo bar"

本文来自:http://blog.yiyun.pro

分类: Docker容器技术 标签:

基于Prometheus做多维度的容器监控

2016年10月28日 评论已被关闭

基于Prometheus做多维度的容器监控

什么是prometheus?

prometheus从官方介绍来说,他是一个开源的系统监控和报警工具,最初由SoundCloud推出。自2012成立以来,许多公司和组织都采用了prometheus,项目有一个非常活跃的开发者和用户社区。它现在是一个独立的开源项目,并独立于任何公司。 

它具有以下特性:

1. 多维度数据模型(由键/值对确定的时间序列数据模型)
2. 具有一个灵活的查询语言来利用这些维度
3. 不依赖分布式存储;单个服务器节点工作。
4. 时间序列的采集是通过HTTP pull的形式,解决很多push架构的问题。
5. 通过中介网关支持短时间序列数据的收集
6. 监控目标是通过服务发现或静态配置
7. 多种数据展示面板支持,例如grafana

怎么使用prometheus监控容器

prometheus监控不同的目标服务需要实现不同的exporter插件,早期的时候,官方出了container-exporter项目,但是现在项目已经停止。推荐使用谷歌的cAdvisor项目作为prometheus的exporter。cAdvisor作为一个监控单机容器的项目,数据较为全面,但是也有很大的问题,例如io等数据没有等等。结合prometheus后就能在整个集群监控查询容器。举个例子,你有一个项目有3个容器分布在三台机器,你怎么监控整个项目的流量,内存量,负载量的实时数据。这就是prometheus的多维度查询解决的问题,数据从3台机器的cadvisor得到每个容器的数据,它的多维度查询语法就能让你得到你想要的数据。

这里假设你有10台机器部署了容器需要监控,你在10台机器上分别部署cAdvisor容器
sudo docker run \
  --volume=/:/rootfs:ro \
  --volume=/var/run:/var/run:rw \
  --volume=/sys:/sys:ro \
  --volume=/var/lib/docker/:/var/lib/docker:ro \
  --publish=8080:8080 \
  --detach=true \
  --name=cadvisor \
  google/cadvisor:latest

找一台机器部署prometheus服务,这里依然使用容器部署:

docker run \
-p 9090:9090 \
--log-driver none \
-v /hdd1/prometheus/etc/:/etc/prometheus/ \
-v /hdd1/prometheus/data/:/prometheus/ \
-v /etc/localtime:/etc/localtime \
--name prometheus \
prom/prometheus

创建/hdd1/prometheus/etc/prometheus.yml配置文件

 my global config
global:
  scrape_interval:     15s # By default, scrape targets every 15 seconds.
  evaluation_interval: 15s # By default, scrape targets every 15 seconds.
  # scrape_timeout is set to the global default (10s).
  # Attach these labels to any time series or alerts when communicating with
  # external systems (federation, remote storage, Alertmanager).
  external_labels:
      monitor: 'container-monitor'
# Load and evaluate rules in this file every 'evaluation_interval' seconds.
rule_files:
   - "/etc/prometheus/rules/common.rules"
# A scrape configuration containing exactly one endpoint to scrape:
# Here it's Prometheus itself.
scrape_configs:
  # The job name is added as a label `job=<job_name>` to any timeseries scraped from this config.
  - job_name: 'container'
    static_configs:
    - targets: ['10.12.1.129:9090','10.12.1.130:9090','10.50.1.92:9090','10.50.1.93:9090','10.50.1.119:9090']
配置文件中 -targets中的端点填写你的实际cadvisor所在的ip和暴露的端口.正确启动后访问ip:9090就能查询数据了哦。

prometheus缺点

1. 单机缺点,单机下存储量有限,根据你的监控量局限你的存储时间。
2. 内存占用率大,prometheus集成了leveldb,一个能高效插入数据的数据库,在ssd盘下io占用比较高。同时可能会有大量数据堆积内存。但是这是可以配置的。

prometheus适用于监控所有时间序列的项目

目前其生态中已经有很多exporter实现,例如:
Node/system metrics exporter
AWS CloudWatch exporter
Blackbox exporter
Collectd exporter
Consul exporter
Graphite exporter
HAProxy exporter
InfluxDB exporter
JMX exporter
Memcached exporter
Mesos task exporter
MySQL server exporter
SNMP exporter
StatsD exporter
你也可以根据你的需要自己实现exporter,完成你需要的监控任务。

本文来自:http://blog.yiyun.pro

分类: Docker容器技术 标签:

使用nginx做 docker swarm集群服务的负载

2016年10月28日 评论已被关闭

使用nginx做 docker swarm集群服务的负载

http://blog.yiyun.pro/使用nginx做-docker-swarm集群服务的负载/

1. 以docker swarm调度的服务的存在方式

我们这里假设需要部署三个相互网络隔离的博客服务blog1,blog2,blog3(本文假设你已经初始化好了docker swarm环境),我们首先创建三个网络分别供以上三个服务使用:

# docker network create --driver overlay blog_network1
# docker network create --driver overlay blog_network2
# docker network create --driver overlay blog_network3

然后创建使用不同网络的三个博客服务:

# docker service create  --network blog_network1 --name blog1  barnettzqg/blog
# docker service create  --network blog_network2 --name blog2  barnettzqg/blog
# docker service create  --network blog_network3 --name blog3  barnettzqg/blog

这样我们已经创建好了最简单的网络隔离的三个博客服务,每一个服务默认启动一个task对应一个容器,你当然可以以以下的方式指定一个服务的task数量来负载,docker swarm实现了自己的负载将服务的访问负载到每一个task上。

# docker service scale blog_network1=3

service对应多个task,每个task对应一个容器(存在于集群的某个主机上),这就是swarm调度的服务存在形式,在service到task的负载swarm已经有了实现。如果service暴露了端口到宿主机,服务就可以直接从集群中每个机器访问到此端口。

2.使用nginx反向代理负载所有博客服务

这里我们使用nginx统一做服务的反向代理负载,不将bolg service直接暴露端口出去。首先我们创建nginx网络:

# docker network create --driver overlay nginx

创建nginx服务,创建文件夹:/ssd/nginx/config和/ssd/nginx/logs :

docker service create -p 80:80 --network nginx --name nginx \
--mount type=bind,source=/ssd/nginx/config,destination=/etc/nginx/conf.d \
--mount type=bind,source=/ssd/nginx/logs,destination=/var/log/nginx \
nginx

然后我们之前创建的三个博客服务使用的不同的网络,nginx也使用的不同的网络,那么我们怎么才能让nginx访问到那三个博客服务呢,我们只需要在创建博客服务的时候将博客服务也加入到nginx网络中,具体创建方式如下:

 docker service create --network nginx  --network blog_network1 --name blog1  barnettzqg/blog

同理重新创建三个博客服务。 这样nginx可以访问博客,但是博客之间相互网络隔离。 nginx中只需要配置使用不同的域名或者端口访问不同的博客,例如以下配置:

server {
        listen 80;
        server_name blog.yiyun.pro;
        location / {
        	proxy_pass  http://blog1;
        }
}

这样就可以使用http://blog.yiyun.pro 访问到集群中的blog1服务。

分类: Docker容器技术 标签:

深入浅出Swarm

2016年10月28日 评论已被关闭

深入浅出Swarm

http://blog.daocloud.io/swarm_analysis_part1/

1.Swarm简介

Docker自诞生以来,其容器特性以及镜像特性给DevOps爱好者带来了诸多方便。然而在很长的一段时间内,Docker只能在单host上运行,其跨host的部署、运行与管理能力颇受外界诟病。跨host能力的薄弱,直接导致Docker容器与host的紧耦合,这种情况下,Docker容器的灵活性很难令人满意,容器的迁移、分组等都成为很难实现的功能点。

Swarm是Docker公司在2014年12月初新发布的容器管理工具。和Swarm一起发布的Docker管理工具还有Machine以及Compose。

Swarm是一套较为简单的工具,用以管理Docker集群,使得Docker集群暴露给用户时相当于一个虚拟的整体。Swarm使用标准的Docker API接口作为其前端访问入口,换言之,各种形式的Docker Client(dockerclient in go, docker_py, docker等)均可以直接与Swarm通信。Swarm几乎全部用Go语言来完成开发,并且还处于一个Alpha版本,目前在github上发布的版本仅有v0.1.0-rc1。然而Swarm的发展十分快速,功能和特性的变更迭代还非常频繁。因此,可以说Swarm还不推荐被用于生产环境中,但可以肯定的是Swarm是一项很有前途的技术。

Swarm的设计和其他Docker项目一样,遵循“batteries included but removable”原则。笔者对该原则的理解是:batteries included代表设计Swarm时,为了完全体现分布式容器集群部署、运行与管理功能的完整性,Swarm和Docker协同工作,Swarm内部包含了一个较为简易的调度模块,以达到对Docker集群调度管理的效果;“but removable”意味着Swarm与Docker并非紧耦合,同时Swarm中的调度模块同样可以定制化,用户可以按照自己的需求,将其替换为更为强大的调度模块,如Mesos等。另外,这套管理引擎并未侵入Docker的使用,这套机制也为其他容器技术的集群部署、运行与管理方式提供了思路。

本文将从以下两点分析Swarm:

  • Swarm架构
  • Swarm命令

2.Swarm架构

Swarm作为一个管理Docker集群的工具,首先需要将其部署起来,可以单独将Swarm部署于一个节点。另外,自然需要一个Docker集群,集群上每一个节点均安装有Docker。具体的Swarm架构图可以参照下图:

17
 

图2.1 Swarm架构图
Swarm架构中最主要的处理部分自然是Swarm节点,Swarm管理的对象自然是Docker Cluster,Docker Cluster由多个Docker Node组成,而负责给Swarm发送请求的是Docker Client。

3.Swarm命令

Swarm架构图可以让大家对Swarm有一个初步的认识,比如Swarm的具体工作流程:Docker Client发送请求给Swarm;Swarm处理请求并发送至相应的Docker Node;Docker Node执行相应的操作并返回响应。除此之外,Swarm的工作原理依然还不够明了。

深入理解Swarm的工作原理,可以先从Swarm提供的命令入手。Swarm支持的命令主要有4个:swarm create、swarm manage、swarm join、swarm list。当然还有一个swarm help命令,该命令用于指导大家如何正确使用swarm命令,本文不再赘述。

3.1 swarm create

Swarm中swarm create命令用于创建一个集群标志,用于Swarm管理Docker集群时,Docker Node的节点发现功能。

发起该命令之后,Swarm会前往Docker Hub上内建的发现服务中获取一个全球唯一的token,用以唯一的标识Swarm管理的Docker集群。

注:Swarm的运行需要使用服务发现,目前该服务内建与Docker Hub,该服务发现机制目前还在alpha版本,站点为:http://discovery-stage.hub/docker.com 。

3.2 swarm manage

Swarm中swarm manage是最为重要的管理命令。一旦swarm manage命令在Swarm节点上被触发,则说明用户需要swarm开始管理Docker集群。从运行流程的角度来讲,swarm经历的阶段主要有两点:启动swarm、接收并处理Docker集群管理请求。

Swarm启动的过程包含三个步骤:

  1. 发现Docker集群中的各个节点,收集节点状态、角色信息,并监视节点状态的变化;
  2. 初始化内部调度(scheduler)模块;
  3. 创建并启动API监听服务模块;

第一个步骤,Swarm发现Docker集群中的节点。发现(discovery)是Swarm中用于维护Docker集群状态的机制。既然涉及到发现(discovery),那在这之前必须先有注册(register)。Swarm中有专门负责发现(discovery)的模块,而关于注册(register)部分,不同的discovery模式下,注册(register)也会有不同的形式。

目前,Swarm中提供了5种不同的发现(discovery)机制:Node Discovery、File Discovery、Consul Discovery、EtcD Discovery和Zookeeper Discovery。

第二个步骤,Swarm内部的调度(scheduler)模块被初始化。swarm通过发现机制发现所有注册的Docker Node,并收集到所有Docker Node的状态以及具体信息。此后,一旦Swarm接收到具体的Docker管理请求,Swarm需要对请求进行处理,并通过所有Docker Node的状态以及具体信息,来筛选(filter)决策到底哪些Docker Node满足要求,并通过一定的策略(strategy)将请求转发至具体的一个Docker Node。

第三个步骤,Swarm创建并初始化API监听服务模块。从功能的角度来讲,可以将该模块抽象为Swarm Server。需要说明的是:虽然Swarm Server完全兼容Docker的API,但是有不少Docker的命令目前是不支持的,毕竟管理Docker集群与管理单独的Docker会有一些区别。当Swarm Server被初始化并完成监听之后,用户即可以通过Docker Client向Swarm发送Docker集群的管理请求。

Swarm的swarm manage接收并处理Docker集群的管理请求,即是Swarm内部多个模块协同合作的结果。请求入口为Swarm Server,处理引擎为Scheduler,节点信息依靠Disocovery。

3.3 swarm join

Swarm的swarm join命令用于将Docker Node添加至Swarm管理的Docker集群中。从这点也可以看出swarm join命令的执行位于Docker Node,因此在Docker Node上运行该命令,首先需要在Docker Node上安装Swarm,由于该Swarm只会执行swarm join命令,故可以将其当成Docker Node上用于注册的agent模块。

功能而言,swarm join可以认为是完成Docker Node在Swarm节点处的注册(register)工作,以便Swarm在执行swarm manage时可以发现该Docker Node。然而,上文提及的5种discovery模式中,并非每种模式都支持swarm join命令。不支持的discovery的模式有Node Discovery与File Discovery。

Docker Node上swarm join执行之后,标志着Docker Node向Swarm注册,请求加入Swarm管理的Docker集群中。Swarm通过注册信息,发现Docker Node,并获取Docker Node的状态以及具体信息,以便处理Docker请求时作为调度依据。

3.4 swarm list

Swarm中的swarm list命令用以列举Docker集群中的Docker Node。

Docker Node的信息均来源于Swarm节点上注册的Docker Node。而一个Docker Node在Swarm节点上注册,仅仅是注册了Docker Node的IP地址以及Docker监听的端口号。

使用swarm list命令时,需要指定discovery的类型,类型包括:token、etcd、file、zk以及<ip>。而swarm list并未罗列Docker集群的动态信息,比如Docker Node真实的运行状态,或者Docker Node在Docker集群中扮演的角色信息。

4.总结

Swarm的架构以及命令并没有很复杂,同时也为希望管理Docker集群的Docker爱好者降低了学习和使用门槛。

俗话说得好,没有一种一劳永逸的工具,有效的管理Docker集群同样也是如此。缺乏场景来谈论Swarm的价值,意义并不会很大。相反,探索和挖掘Swarm的特点与功能,并为Docker集群的管理提供一种可选的方案,是Docker爱好者更应该参与的事。

本文初步介绍Swarm,并涉及架构与命令,下期将带来Swarm的具体使用,以及Swarm的架构剖析。

5.作者介绍

孙宏亮,DaoCloud初创团队成员,软件工程师,浙江大学VLIS实验室应届研究生。读研期间活跃在PaaS和Docker开源社区,对Cloud Foundry有深入研究和丰富实践,擅长底层平台代码分析,对分布式平台的架构有一定经验,撰写了大量有深度的技术博客。2014年末以合伙人身份加入DaoCloud团队,致力于传播以Docker为主的容器的技术,推动互联网应用的容器化步伐。邮箱:allen.sun@daocloud.io

6.参考文献

1.http://github.com/docker/swarm
2.http://technolo-g.com/intro-to-docker-swarm-pt1-overview/
3.http://technolo-g.com/intro-to-docker-swarm-pt2-config-options-requirements/

分类: Docker容器技术 标签:

工程师SwarmKit初体验 比传统集群工具更方便

2016年10月28日 评论已被关闭

工程师SwarmKit初体验 比传统集群工具更方便

https://www.baidu.com/s?wd=SwarmKit&tn=87048150_dg&ie=utf8

Docker在6月7日发布了SwarmKit,随后在上周的DockerCon大会中发布Docker1.12版本,宣布SwarmKit引入编排功能,终于为用户解决容器的集群管理、分布式应用在容器集群上的编排管理的两大难点。

在SwarmKit的帮助下,我们得以将容器从只能部署在单一机器之上,升级为能够将多种复杂的容器应用广泛部署于大量设备当中。通过SwarmKit项目,使原生Docker Native即支持集群与分布式应用系统编排。

接下来我会从SwarmKit的整体架构、试用体验以及与其他容器管理软件整体上的比较,这三个方面进行分享。

SwarmKit功能介绍

SwarmKit项目是Docker公司的一个开源项目,主要用来提供容器集群以及编排能力。其主要功能包括节点发现、基于raft算法的一致性和任务调度等。

如下图所示,SwarmKit通过Containerd类似的方式接入Docker Engine,最终通过新的Docker API对外提供容器集群服务。

整体架构

目前来说SwarmKit还没有对外发布对于集群操作的API。但是,通过CLI的方式来进行集群的相关管理操作也是非常的简单。比如,通过在服务器上运行SwarmKit工具的swarmd命令后,即可将其加入到服务器集群中,是该服务器成为集群中的一个节点。SwarmKit的节点分为两类:

工作节点(Worker):负责通过执行器运行任务。SwarmKit的默认执行器为Docker容器执行器(Docker Container Executor)。

(1)内建分布式存储,不要额外的数据库

(2)支持Rolling update

(3)容器高可用,支持Zero applicaton downtime

(4)通过TLS保证了节点之间通讯的安全

管理节点(Manager):负责接收和响应用户请求,将集群状态调节到最终状态。在SwarmKit中,用户可以动态调整节点的角色,即在Manager和Worker之间转换。

主要特征

(1)服务状态一致性: SwarmKit会不断对比Worker节点的2个状态:期望状态和实际状态。当一个节点的这两种状态不一致时,SwarmKit会自动将服务中的任务调度到其他节点,以保证服务的正常运行。

(2)服务类型:目前SwarmKit支持两种服务类型:

复制服务:SwarmKit通过命令行参数可以在Worker节点上启动期望数量的服务实例,并通过调度策略合理地运行在不同的节点上。

全局服务:SwarmKit会在集群中所有可用节点上启动一个任务。

(3)配置更新:用户可以在任何时间对服务的一个或者多个配置进行更新,甚至更新整个服务的版本。在对某个服务执行完配置更新的命令后,SwarmKit会协调升级服务中的所有任务。默认策略是多个任务同时升级。现有的更新策略有:并发更新和延迟更新。

并发更新:定义同时更新的任务数量,根据不同任务更新的实际结果来修正更新任务的最终状态,达到状态的一致。

延迟更新:设置一组更新完成之后的最小等待时间。当配置升级时,SwarmKit会重启并等待任务变为运行状态,并在延迟结束后继续执行后续的更新;

(4)重启策略:用户可以定制重启的条件、延迟和最大尝试次数。SwarmKit会检测任务状态,并按照用户定义的条件进行重启,同时SwarmKit会决定是否在不同节点启动任务,避免失效节点对服务产生影响。

(5)内置路由机制:负载均衡对大规模集群来说是非常重要的,SwarmKit的结合使得Docker Engine自身支持路由功能,而与原生ovelay网络的结合,效果更加显著。容器原生的负载均衡,无需额外的集群设置,就可以兼容用户现有的负载均衡服务。通过IPVS与内核联合,实现可靠的负载均衡。

集群管理

SwarmKit的集群管理主要有以下特点:

(1)状态存储:SwarmKit基于Raft算法在内存中维护集群的状态一致性,并能够在集群状态发生异常时迅速作出调度调整;

(2)拓扑管理:SwarmKit支持通过API或者命令行方式来动态修改节点角色(Worker/Manager);

(3)节点管理:操作者可以修改可用节点的状态。例如可以设置节点状态为Paused,以避免在该节点上创建新的任务;或者设置为Drained状态,除了禁止创建新任务外,当前节点上的其他任务也会被调度到其他节点上。

任务调度

SwarmKit在任务调度上主要有以下特点:

(1)资源感知:SwarmKit能够感知可用节点上的资源利用情况,并以此分配和执行任务。

(2)资源约束:用户可以通过约束表达式,将任务调度到符合表达式的节点上。对节点的约束条件包括节点ID、名称和标签等。

(3)调度策略:目前SwarmKit默认采用Spread调度策略;在满足约束条件和资源需求的前提下,尽可能地将任务调度到负载最低的节点。

安全设计

SwarmKit在安全设计方面有以下特点:

(1)所有节点采用TLS相互通信。新的节点通过Swarm管理节点进行认证加入进来。

(2)加入策略:节点加入集群可以通过自动允许、手动允许或者通过一个密钥来加入集群。

(3)循环认证:TLS循环认证和重新加载在每个节点上都是透明的,用户可以设置循环认证和重新加载的频率(默认是3个月,最低是30分钟)。

SwarmKit初体验

二进制文件构建

由于目前SwarmKit刚刚开源,没有稳定的二进制分发版,所以需要我们自行构建。构建过程非常简单,主要分为:环境搭建、源码下载和构建两个步骤。

环境搭建:SwarmKit的源码在Github上,采用Go语言开发,所以要构建二进制文件,必须搭建Go开发环境。这里要求Go开发环境必须是1.6及以上版本。

首先在https://golang.org/网站下载go1.6.2.linux-amd64.tar.gz,并解压到/usr/local下面。

配置环境变量

GOROOT是Go的安装目录;GOPATH是开发者存放Go代码的目录。

配置好环境变量后,在终端输入Go,出现如下界面说明安装成功:

源码下载和构建:

如果机器安装了Git,直接输入如下命令进行构建:

$ go get github.com/docker/swarmkit/…

如果没有安装git,在github上下载SwarmKit源码,并在自己的work目录下面创建/src/github.com/docker/目录,把SwarmKit源码放在这个目录下,执行以下命令构建:

$ make binaries

构建完成之后就会在bin目录下面产生如下的四个二进制文件:

swarmd是一个swarmkit daemon程序,用来运行manager和worker。swarmctl是一个命令行工具,用来访问swarm manger,当然最终在Docker1.12可通过Docker命令访问。

SwarmKit具体使用:

拷贝这4个文件分别到我们将要运行SwarmKit的三台主机的/usr/bin下面。

(1) 使用SwarmKit

这里选择三台主机运行SwarnKit,依次为:

192.168.1.220 Manager

192.168.1.221 Worker

192.168.1.222 Worker

在执行命令之前确保/tmp下面不存在node-N

在Manager节点执行如下命令:

$ swarmd -d /tmp/node-1 –listen-control-api /tmp/manager1/swarm.sock –hostname node-1

需要后台运行采用nohup启动。如果出现无法执行二进制文件,说明构建二进制文件机器的环境和启动swarmd的机器不一样,需要按照不同的环境重新构建。

依次在Worker节点上执行如下命令:

$ swarmd -d /tmp/node-2 –hostname node-2 –join-addr 192.168.1.220:4242

$ swarmd -d /tmp/node-3 –hostname node-3 –join-addr 192.168.1.220:4242

如果以上命令都执行成功,下面就可以在管理节点的终端执行swarmctl命令,来管理整个docker集群。

$ export SWARM_SOCKET=/tmp/manager1/swarm.sock

查看节点信息:

$ swarmctl node ls

创建服务:

$ swarmctl service create –name redis –image redis:3.0.5

列出服务:

$ swarmctl service ls

检查服务:

$ swarmctl service inspect redis

这里看到了redis服务在node-1上面运行,这时就可以采用docker ps在node-1服务器上看到运行的redis容器。

更新服务:

$ swarmctl service update redis –replicas 3

这就是SwarmKit的复制服务。这里看到了在3各节点分别运行了redis,这时可以分别在不同机器上通过docker ps命令查看正在运行的容器。node-2节点的Last State是PREPARING,说明此时node-2还没有启动redis容器。这里和docker一样,启动一个容器,如果本地没有这个容器的镜像,需要在docker hub上拉取镜像,当拉取完成后,容器将正常启动,最新的状态也会更新为RUNNING。

更新redis:

$ swarmctl service update redis –image redis:3.0.6

这就是SwarmKit的配置升级。这里是以任务的方式执行的,Last State在容器最终更新完成后变成RUNNING。

节点管理:

这里我们使node-1进入不可用状态,查看节点的变化情况:

$ swarmctl node drain node-1

这时任务已经被迁移到node-2和node-3节点上,成功完成了任务的迁移,保证了SwarmKit服务的一致。

通过以上对SwarmKit的使用,让我们明显的感觉到了SwarmKit的优势。SwarmKit是容器集群领域的新成果,直接集成在Docker Engine中,通过新的Docker API提供集群服务,相比于传统的集群管理工具更加方便。

到目前为止,我们更多的是采用Swarm、Mesos或者Kubernetes支持大规模的生产基础设施,从而实现容器管理。而SwarmKit给我们带了新的选择,我们需要进一步的扩展以支持其他环境。当前SwarmKit还处于一个初步发展阶段,与Swarm、Kubernetes和Mesos相比,在调度方案上还远不能及,我们期待SwarmKit的下一个版本能带给我们更多的惊喜。

本文还在微信公众号发表:http://mp.weixin.qq.com/s?__biz=MzIzNzA5NzM3Ng==&mid=2651856819&idx=1&sn=45c7a0ca414bee039afe02a0a1f9114a#rd

分类: Docker容器技术 标签:

Docker发布集群工具SwarmKit

2016年10月28日 评论已被关闭

Docker发布集群工具SwarmKit

http://www.infoq.com/cn/news/2016/06/Docker-SwarmKit

最近Docker公司开源了Docker集群管理和容器编排工具SwarmKit,其主要功能包括节点发现、基于raft算法的一致性和任务调度等。

基本概念

服务器上运行SwarmKit工具的swarmd命令后,即可将其加入到服务器集群中,该服务器就成为集群中的一个节点。SwarmKit将节点分为两类:

  • 工作节点负责通过执行器运行任务。SwarmKit的默认执行器为Docker容器执行器(Docker Container Executor);
  • 管理节点负责接收和响应用户的请求,将集群状态调节成最终状态。

用户可以动态调整节点的角色。

任务被组合成为服务,服务定义了任务类型和任务运行和更新的方式(如任务运行数量、启动间隔等)。

特性

服务编排

SwarmKit在服务编排方面的特性主要有:

  • 服务状态一致性:SwarmKit会不断对比服务期望状态和实际状态,发现二者不符时(如服务扩容、节点失效),SwarmKit会自动将服务中的任务调度到其他节点。
  • 服务类型:目前SwarmKit支持两种服务类型
    • 复制型服务(Replicated Services),针对这类服务SwarmKit会在节点上启动期望数量的副本;
    • 全局服务(Global Services),这类服务SwarmKit会在所有可用几点上启动一个任务;
  • 配置项升级:用户可以在任何时候修改服务的一个或多个配置。当配置被修改后,SwarmKit会协调升级服务中的所有任务,默认的升级策略是批量同时升级。目前支持的升级策略选项有:
    • 并行度:定义并行更新的任务数量;
    • 延迟:设置一组更新完成之后的最小等待时间。当配置升级时,SwarmKit会重启任务,并且等待任务状态为运行中,再等待配置的延迟后,继续执行后续的更新批次;
  • 重启策略:用户可以定制重启的条件、延迟和最大尝试次数。SwarmKit会检测任务状态,并按照这些配置进行重启,同时SwarmKit会决定是否在不同节点启动任务,避免失效节点对服务产生影响。

调度

SwarmKit在调度功能上功能有:

  • 资源感知:SwarmKit能够感知节点上的资源,并以此分配和执行任务。
  • 资源约束:用户可以通过约束表达式,将任务约束到符合表达式的节点上。对节点的约束条件包括节点ID、名称和标签等。
  • 调度策略:目前SwarmKit实现的调度策略是在满足约束条件的前提下,尽可能的分配到负载最低的节点。

集群管理

SwarmKit对于集群及其节点的管理支持:

  • 状态存储:SwarmKit在内存中维护集群的状态,并能够在集群状态发生异常时迅速作出调整;
  • 拓扑状态管理:SwarmKit支持通过API或者命令行动态修改节点角色;
  • 节点管理:SwarmKit API支持用户修改节点状态。例如可以将节点状态设置为中止(Paused),以避免在该节点上创建新的任务;或者设置为枯竭(Drained)状态,除了禁止创建新任务外,当前节点上的其他任务也会被调度到其他节点上。

总结

相比于之前的Swarm,这次发布的SwarmKit使用更加方便,无需再依赖外部协调软件进行服务发现。同时对容器运行进行了抽象,API更加间接。SwarmKit特性和其他服务编排框架如mesos,kubernetes等比较类似,目前SwarmKit还在活跃开发中,能否攻城略地,让我们拭目以待吧。

通过Docker容器运行持续集成/持续部署

2016年10月28日 评论已被关闭

通过Docker容器运行持续集成/持续部署

http://www.open-open.com/lib/view/open1435218140028.html#articleHeader1

对于docker主流的应用场景:持续集成和持续部署(CI/CD)大家也许并不陌生.这篇文章从独特的视角阐述了如何利用各种云平台构建属于自己的CI/CD容器,笔者还自己扩展了Gitlab CI引擎,对CI感兴趣的同学对这个文章应该很感兴趣.

我曾经使用Docker了一段时间,在过去的一年里伴随着众多的Docker容器涌入,帮助用户们更容易的部署Docker容器到生产环境中。一 些工具是第三方公司提供,当然也包括Docker公司自己的容器工具(例如:Docker Swarm, Docker Machine, 和 Docker Compose)。尽管如此,最近我在测试一种新的Docker工作流,它可以允许我推送代码并测试, 构建项目,并且部署在生产环境下的Docker宿主机中。

接下来隆重介绍我的新工具 bar service, ThreeBar ①,一个可以在Heroku上运行持续集成/持续部署(CI/CD)系统。通常情况下,新开发的代码部署到服务器遵循下面的流程:

  1. 创建一个本地组件
  2. 推送代码到git仓库的feature/development分支
  3. Shippable ,一个持续集成引擎,一旦检测到有的提交(commit),通过pull获取最新的代码并且运行相关的测试
  4. 如果测试全都通过了等着被部署到生产环境中,就会创建一个合并(merge)分支的请求并且执行该合并(merge)
  5. Shippable 一旦检测到有新的提交到远程master分支,同时会执行测试,并且推送源码到Heroku的git仓库中
  6. Heroku 将会自动构建这个应用程序并且部署它。

这个工具真的可以方便、快捷的部署项目并且保证所有部署到生产环境的代码都经过了测试而且是可靠的。

尽管如此,还是由一个问题,那就是大规模部署Heroku需要花费高昂的费用。选择使用heroku,你将会获得heroku提供的免费使用优惠 ②,一个标准的512内存的由heroku提供的Dyno容器只需要35$。公平的说,heroku提供的虚拟主机服务已经够实惠了,但是一些应用的复杂 程度要求heroku提供更灵活的定制化需求,收取一定费用也无可厚非。

Docker,当然可以替代heroku,提供相应的代码部署服务。但是上面谈到的问题仍旧存在。当你的代码需要部署的时候,频繁手动启动和关闭服务是得不偿失的。让我们来比较一下不同持续集成/持续部署引擎和docker相比有什么不同。

寻找解决方案

Docker并不是第一个也不是最后一个端到端的持续集成工作流解决方案。因此我们需要将众多不同的技术组合到一起用来完成我们想要的功能。下面将会介绍三个主流的提供构建引擎的服务:一个CI/CD的测试运行引擎,一个web容器,一个容器适配器。

CI/CD 服务器,测试运行引擎

当我们选择一个CI/CD服务,你必须确定他们必须支持Docker容器的构建。下面的这些服务都包含了这一功能:

当然还有一些其他的服务,包括大名鼎鼎的Jenkins CI server。这里你可以自己去搜索这些服务。一些服务在容器上运行构建,但是他们相互之间是完全独立的。稍后你就会看到,你可以在Docker-in- Docker上运行服务,同时可以使用在Docker 容器中运行的其他服务。

在我的试验中,我选择了和Gitlab 版本管理服务器端同时运行GitLab CI 系统。通过Gitlab版本管理服务器,我可以很清楚的看到每次commit。选择Gitlab不仅是因为他是一个免费的开源源码 托管仓库和对托管在上面的项目提供的 持续部署引擎 ,同时也是一个通过安装gitlab运行你自己的服务的开源软件。

如果你选择使用Gitlab CI System搭建你的持续集成框架,你必须提供属于自己的测试运行服务。宿主机的持续集成软件只能运行特定的测试服务,实际上它自己并不能自己执行测试任 务,通常都是启动由本机提供相应的测试服务来执行的,你不光可以通过服务提供商启动引擎或者你直接运行你本机上的服务(虚拟机VM或Docker容器).

服务器托管提供商

当然你同时也需要一个服务器托管提供商让Docker守护进程可以在它之上运行。不幸的是,使用Docker意味着经常需要运行和管理自己的服务 器,也就是你将要负责这个主机的运维。但是,我想通过下面的内容说明,你可以在Docker运行一个高可用、多数据中心架构,这意味着即便是停机一个小时 也不会像以前那样对业务影响那么巨大。

常用的服务器托管提供商包括下面的几个③:

业务流程

即是你有了一套构建好了的Docker容器和能够运行docker守护进程的服务器。你还是需要一个能够被轻易启动的容器并且能够在构建一个新镜像的时候能重复部署他们。正如我最近正在使用的名叫Tutum 的业务流程服务。

目前, Tutum 是一个能帮助你管理你的容器部署工作流的服务形式。与此同时,你还能在各种云平台上快速动态增加节点,创建新服务,通过一个私有的register来部署你的应用。

此外, Tutum 还为你的容器创建了一个私有网络,意味着可以通过你的Tutum账户你的Docker容器拥有自己的私有固定IP地址并且通过路由来访问其他容器。无论你 的物理机是否在同一个数据中心,还是通过世界各地的不同的服务器托管提供商。它都将允许你创建一个基于多服务器、多云平台的弹性的解决方案。如果你之前见 过 Flannel by CoreOS , Tutum 的私有网络和它差不多。

我一直在寻找类似上面谈到的这种服务。就在前不久,我刚做了一个实验:在多容器docker之间通过vpn创建一个P2P网络。这是很久之前的docker网络配置达不到的需求,但是现在 Tutum 做到了。

Tutum 同时也整合了CI/CD组件,并且支持git推送(push)。当Tutum 完成功能的时候,它可能成为唯一的你需要包含的到源码仓库中的其他服务。

Tutum 拥有我们需要进行CI/CD的几个关键组件:

  • 一个私有的为容器镜像准备的注册中心
  • 当新的镜像推送到注册中心的时候重新部署容器
  • 简便的容器扩容(在界面视图上,可以通过滑动N或M的方式调整容器大小)
  • 在Tutum的界面上添加节点

其他我们值得关注的组件:

*在对一个web应用容器缩放后,基于自省的方式的DNS动态解析。举个例子,你的haproxy路由会自动发现新增容器并且添加到路由列表中。

  • 私有的网络覆盖
  • 不再受不同云供应商的限制,创建自己的节点

给所有东西组装到一起

下面就挑干货说下我的实验过程:

  • 宿主机使用Gitlab搭建的源码远程仓库
  • 宿主机使用Gitlab CI搭建的CI/CD引擎
  • RunAbove作为服务器提供商对所有CI/CD运行引擎的容器托管④
  • Tutum 作为业务流程和服务的管理服务提供

当所有的事情结束,也组装完毕,git的提交记录活动图,如下图所示:

通过Docker容器运行持续集成/持续部署

部署Tutum 代理

正因为如此,我们事实上是使用Tutum 去部署GitLab CI runners。我给你的建议是,先安装Tutum agents。启动所有你希望使用的服务,这样在 Tutum 的仪表盘上就能看到Bring your own node字样的按钮。点击它,你将会收到一个如下面所示的命令行:

curl -Ls https://get.tutum.co/ | sudo -H sh -s XXXXXXXXXXXXXXXXXXX通常在某一个节点运行上述命令自动添加到你的Tutum账户,与此同时进程也会自动添加到其他节点(每次当你点击Bring your own node按钮的时候)。

一旦Tutum agent 安装到你的所有节点上,你将会在仪表盘上看到它. 在这一点上,你也许想给这个节点贴上适当的标签. 允许对应的服务器在哪个节点上运行。举个例子,你可能有一组节点标记为tag或production目的是为了创建一套环境,亦或者是用来做持续集成的一个节点标记,这些只能在宿主机上运行。

你可以通过点击节点名称来标记一个节点,添加的标记将会显示在左侧边栏。

部署一个Gitlab CI 运行引擎

现在你可以通过Tutum 来部署一个Gitlab CI 运行引擎.然而,我们需要一种特殊类型的持续运行引擎-需要能够在这个容器中运行Docker并且能够构建我们自己的Docker镜像.

你可能想,这怎么可能呢?假如我们使用Tutum运行Gitlab CI 引擎,它只能运行在容器里。那么问题来了,如何在Docker容器里运行Docker呢?

其实这完全可以做到。事实上,我们可以运行在你能想象到的更深层Docker中. 我们的Docker容器架构如下图所示:

通过Docker容器运行持续集成/持续部署正如你所看到的,在我们的节点的Docker容器里Tutum运行GitLab CI引擎。此外,该GitLab CI引擎实际上使用Docker构建镜像并运行测试,这意味着我们有两个嵌套层次.

通过fork GitLab CI Runner,我已经建立了相应功能的分支.这样就可以有效的跟踪在 github 和官方Docker注册中心的变更.

在建立你的GiLab CI runner前,确保你已经存在一个GitLab的实例仓库,并且能够同时运行GitLab CI 引擎.正如前面提到的,你可以建立自己的实例,或者直接使用gitlab官方提供的免费托管仓库和持续部署服务.

一旦你注册了gitlab仓库。你所做的只需要通过点击链接你的Gitlab CI 账号.在你关联了Gitlab CI账号之后,你将会通过Gitlab的仪表盘看到你的gitlab仓库列表,并且通过点击”Add project to CI” 按钮来添加你的项目到Gitlab CI 引擎中.点击完毕后,你就会在gitlab的仪表盘上看到你新添加的项目信息了.如下图所示:

通过Docker容器运行持续集成/持续部署如果你轻戳gitlab的用户界面,你将会注意到一个菜单标题为”Runners”.在这个页面有一个注册标记,同时还有如何创建一个新 的”Runner”的功能说明. 在下面的例子中,我将会使用Tutum部署我们的Gitlab CI 镜像.确定你已经复制了注册标记和Gitlab CI的url地址-一会你将会用到他们.

在你的Tutum界面上,创建一个新的服务.在Tutum中服务的概念是一个Docker容器组,他们使用相同的软件并运行着相同配置.

每个服务可以有零个或者多个容器在同一时间运行,并且Tutum将会管理你所有节点的协调和缩放工作.

在启动向导的第一个界面,你将会看到几个标签,让你选择不同来源的Docker镜像源.Tutum拥有一个内置的,私有的注册中心,通过搜索其他 注册中心同时支持一些具有特定功能的镜像,当然这里也包括Docker的官方镜像.切换到”公共镜像”选项卡,搜索”wizardapps/dind- gitlab-ci-runner”镜像,这就是我前面描述的在github上fork的GitLab CI 引擎源码仓库中我自己建立的分支.

你一旦确定选择了镜像,你将会看到一个界面上面你对两个容器之间调度的功能选项和一些基本配置。对于部署策略,虽然默认的设置也可以运行持续集 成,但是我建议还是通读下Tutum官方的说明文档。You also will likely want to leave the number of containers at 1 unless you wish to do parallel builds.如果你先前已经对部署在Tutum的节点打了对应的标签,请确保在”Delpoy Tags”输入框输入了正确的标签名称.从本质上讲,Tutum会努力寻找所有满足你要求”Delpoy Tags” 中声明的标签,并且部署他们到一个节点.

下图说明当你第一次必须要改动的一个重要的配置信息,这是在”Advanced Options”部分的”Privileged Mode”选项,Docker需要选中这个选项,这样保证Tutum可以很容易的获得该信息.

通过Docker容器运行持续集成/持续部署在配置好私有模式后,你将会看到下一个屏幕-有关环境变量配置信息.

像Docker命令行一样,Tutum允许你声明一个环境变量使之可以在你的Docker容器里使用.

不仅如此,在Tutum中,每一个部署的容器都可以使用这个环境变量.尽管我们不会再Gitlab CI 引擎上使用link功能,我们使用的是Tutum提供的动态link,容器依然允许使用其他容器中的环境变量.

下面是三种需要设置的重要的环境变量:

  • REGISTRATION_TOKEN: 注册信息就是之前我们在Gilab CI 中拷贝的”Runner”.
  • CI_SERVER_URL: 在Gitlab CI页面上之前提供给我们的url地址.如果你使用的是官方提供的gitlab CI服务,直接填写” https://ci.gitlab.com/”.
  • GITLAB_SERVER_FQDN:这里声明的是gitlab 的域名,这是用来执行一个ssh-keyscan.如果你用的是官方的托管服务,请填写 “ci.gitlab.com”.

在配置完这些变量之后,终于可以”创建并部署”我们的服务了.

一旦你的容器启动完毕, 你可以返回GitLab CI的 “Runners” 页面并且你看到一个新的入口. 现在你可以着手准备建立 GitLab CI 任务吧.

创建一个GitLab CI 任务

终于到最后一步了,我们在Gitlab CI 上添加一个实际的脚本目的是建立一个 持续集成/持续部署的工作流.现在,这将取决于你的实际项目的种类,但大体方向应该是相同的,你会使用Docker镜像来构建Docker容器,然后上传 到你的镜像库.在这种情况下,将会上传到Tutum提供的私有镜像库.

在”工作”选项卡中,Gitlab CI工作可以进行修改.在这个部分,有两个不同的子选项-“test”和”deploy”.正如他们名字所暗示的,测试脚本通常用来运行单元和集成测试. 部署脚本只运行一旦测试完成后的特定分支.这样就可以允许你在每次提交(commit)后运行你的测试脚本,与此同时部署脚本当且仅当所有测试全部通过的 时候部署远程master分支.

下面是脚本实例:

“`

docker login-u[USERNAME]-e[EMAIL]-p=”[PASSWORD]”tutum.co

Build the Docker image and tag it for Tutum

docker build-twizardapps/app.

docker tag-fwizardapps/app tutum.co/wizardapps/app:latest

“`

上面的测试脚本并没有实际运行任何测试,但是他确能为我们的应用程序构建Docker镜像并打上对应的标签.如果你在初始化阶段使用自己的脚本, 请确保你的用户名,邮箱,密码和Tutum上的注册信息报纸一致.因为Tutum提供的是一个私有Docker注册中心,确保你的测试脚本能通过相应的校 验⑤.

然后,我们还可以创建一个部署脚本,实际上是推送我们的镜像到Tutum的注册中心,并开始构建.

docker push tutum.co/wizardapps/app

自动部署

到了这一步,你的系统应该已经构建成功并运行,新代码应该可以持续集成并上传到Tutum的注册中心.剩下的工作就是在Tutum上创建你自己的服务,确保重启后还可以继续使用.

这和我们创建Gitlab CI 服务类似,所不同的是我们让服务”私有化”,我们只需要打开”Auto Redeploy”开关即可.配置所有的服务端口,环境变量,链接和卷标,然后点击一下部署即可.

恭喜你,你现在已经拥有了只有在经过测试后,可以快速进行持续部署,自动化部署的Docker 应用程序.

其他资源

GitLab CI Multi-Runner 地址: https://github.com/ayufan/gitlab-ci-multi-runner

我们通过在Tutum里建立每个项目上都需要的持续集成 “服务”,可以很快上手.作为一种替代方案,你可以尝试使用GitLab CI Multi-Runner,这个项目通过一个配置文件允许多个项目同时进行构建。

①. 我有一些很酷的东西和大家分享,这就是ThreeBar-一个远远超出你想象的工具.一旦你做好准备加入,你将会发现Docker持续-部署-应用的强大功能。

②. Heroku 运营模式,您只需要按小时支付使用费.每一个”虚拟机”运行你的代码被称之为”Dyno”,你可以仅仅通过运行一个命令就可以做到一键部署,例如web服 务器或者其他请求队列服务.你将会每个月获得750小时的”Dyno”免费使用权.这意味着如果你愿意的话可以在Heroku上运行一个免费的web服务 器.

③. 我个人使用了以下所有的服务器提供商,我也通过博客链接点击获得了一些收入.但是,很可惜,任何一个服务器提供商都不会允许你在创建你自己Docker服务并运行在Linux实例上.

④. RunAbove的沙箱是一个伟大的实验,因为在它上面有大量的RAM,SSD存储,并且花费极低-每月只有3美金在一个2G内存的服务器上.尽管如此,在那个时候他们不被SAL所接受,因此你只能选择其他的服务提供商.

⑤. 此时此刻,你必须把你的Tutum的账号和密码直接扔到脚本中.很不幸的是,Tutum不提供这样的单独密码注册表API,所以这个方案也因此留下一个潜在的安全漏洞.

分类: Docker容器技术 标签:

Docker应用教程-挂载运行中的docker容器中挂载文件系统

2016年10月28日 评论已被关闭

Docker应用教程-挂载运行中的docker容器中挂载文件系统

http://www.simapple.com/387.html

很多人可能都在问docker的问题,关于怎么操作一个已经启动的docker容器的文件系统,首先我发现这非常困难,因为 mnt的命名空间。

为了登录进入一个已经启动的docker容器,我们需要这么做:

  •  使用nsenter来在临时挂载点上挂载整个docker容器的文件系统。
  • 创建一个特定目录的绑定挂载来当作卷来使用。
  • 卸载临时挂载。

好吧,开始实践。

启动一个名为charlie的docker实例:

$ docker run --name charlie -ti ubuntu bash

我想要将目录 /home/jpetazzo/Work/DOCKER/docker to /src 挂载到我的docker容器中。

nsenter

首先,需要nsenter,通过docker-enter帮助脚本来操作。因为想要挂载文件系统到docker容器中,处于安全原因,我们的docker容器是不允许这么做的。使用nsenter,我们就可以在docker容器中执行任意的命令,而不会受到任何安全限制的干扰,直接获取docker容器的root权限,如何获取docker容器的方法 就是这样

安装nsenter,通过docker-enter安装nsenter:

$ docker run --rm -v /usr/local/bin:/target jpetazzo/nsenter

 

使用我们的docker文件系统

想要挂载宿主主机中的目录 (/home/jpetazzo/Work/DOCKER/docker) 在docker中。

要找到docker文件系统的目录。

首先使用readlink查看docker 目录的挂载位置

$ readlink --canonicalize /home/jpetazzo/Work/DOCKER/docker
/home/jpetazzo/go/src/github.com/docker/docker

设置环境变量:

$ HOSTPATH=/home/jpetazzo/Work/DOCKER/docker
$ REALPATH=$(readlink --canonicalize $HOSTPATH)

查看docker文件系统的挂载情况df:

$ df $REALPATH
Filesystem     1K-blocks      Used Available Use% Mounted on
/sda2          245115308 156692700  86157700  65% /home/jpetazzo

指定指定docker 文件系统的环境变量

$ FILESYS=$(df -P $REALPATH | tail -n 1 | awk '{print $6}')

查看docker容器中的设备情况

因为现在没有绑定挂载或者使用 BTRFS,所以我们要查看/proc/mounts 来找到这个目录的设备文件 /home/jpetazzo 。

$ while read DEV MOUNT JUNK
> do [ $MOUNT = $FILESYS ] && break
> done </proc/mounts
$ echo $DEV
/dev/sda2

通过设备信息找到挂载情况。

$ while read A B C SUBROOT MOUNT JUNK
> do [ $MOUNT = $FILESYS ] && break
> done < /proc/self/mountinfo 
$ echo $SUBROOT
/jpetazzo

很好,我们现在知道需要挂载 /dev/sda2,到这个目录 /jpetazzo, 从这个位置 指向我们需要的任何目录。

设定目录

$ SUBPATH=$(echo $REALPATH | sed s,^$FILESYS,,)

查看设备号。

$ stat --format "%t %T" $DEV
8 2

设置设备信息

$ DEVDEC=$(printf "%d %d" $(stat --format "0x%t 0x%T" $DEV))

将这些步骤集合

我们就是要验证docker容器中的路径和主机是不是一置

 

$ docker-enter charlie -- sh -c \
> "[ -b $DEV ] || mknod --mode 0600 $DEV b $DEVDEC"

创建临时挂载点挂载文件系统

$ docker-enter charlie -- mkdir /tmpmnt
$ docker-enter charlie -- mount $DEV /tmpmnt

确定文件系统存在挂载卷

$ docker-enter charlie -- mkdir -p /src
$ docker-enter charlie -- mount -o bind /tmpmnt/$SUBROOT/$SUBPATH /src

清理临时挂载

$ docker-enter charlie -- umount /tmpmnt
$ docker-enter charlie -- rmdir /tmpmnt

 

下面是一个简单实例脚本:

 

#!/bin/sh
set -e
CONTAINER=charlie
HOSTPATH=/home/jpetazzo/Work/DOCKER/docker
CONTPATH=/src

REALPATH=$(readlink --canonicalize $HOSTPATH)
FILESYS=$(df -P $REALPATH | tail -n 1 | awk '{print $6}')

while read DEV MOUNT JUNK
do [ $MOUNT = $FILESYS ] && break
done </proc/mounts
[ $MOUNT = $FILESYS ] # Sanity check!

while read A B C SUBROOT MOUNT JUNK
do [ $MOUNT = $FILESYS ] && break
done < /proc/self/mountinfo 
[ $MOUNT = $FILESYS ] # Moar sanity check!

SUBPATH=$(echo $REALPATH | sed s,^$FILESYS,,)
DEVDEC=$(printf "%d %d" $(stat --format "0x%t 0x%T" $DEV))

docker-enter $CONTAINER -- sh -c \
         "[ -b $DEV ] || mknod --mode 0600 $DEV b $DEVDEC"
docker-enter $CONTAINER -- mkdir /tmpmnt
docker-enter $CONTAINER -- mount $DEV /tmpmnt
docker-enter $CONTAINER -- mkdir -p $CONTPATH
docker-enter $CONTAINER -- mount -o bind /tmpmnt/$SUBROOT/$SUBPATH $CONTPATH
docker-enter $CONTAINER -- umount /tmpmnt
docker-enter $CONTAINER -- rmdir /tmpmnt

Docker 应用教程,致力于做最实用的docker教程。

taxonomyextra:

转载请注明来自:简果网

转载请注明本文链接:Docker应用教程-挂载运行中的docker容器中挂载文件系统(link is external)[http://www.simapple.com/387.html]

分类: Docker容器技术 标签:

Docker 无法启动的问题解决

2016年10月28日 评论已被关闭

Docker 无法启动的问题解决

https://my.oschina.net/u/1188877/blog/422405?p=1

摘要: Docker报错Error running DeviceCreate (createPool) dm_task_run failed,无法启动问题解决

首先看报错信息:

~  sudo docker -d
[sudo] password for prat0318:
2014/06/10 02:26:34 docker daemon: 1.0.0 63fe64c; execdriver: native; graphdriver:
[29daee74] +job initserver()
[29daee74.initserver()] Creating server
[29daee74] +job serveapi(unix:///var/run/docker.sock)
2014/06/10 02:26:34 Listening for HTTP on unix (/var/run/docker.sock)
Error running DeviceCreate (createPool) dm_task_run failed
[29daee74] -job initserver() = ERR (1)
2014/06/10 02:26:34 Error running DeviceCreate (createPool) dm_task_run failed

Docker无法启动 /etc/init.d/docker start 后又回莫名其妙挂掉,如下

[root@localhost docker]# service docker status
docker dead but subsys locked

可能还有些会报错说pid啥的,统一解决方案如下:

rm /var/run/docker.*   
rm /var/lock/subsys/docker

此时再查看docker的状态便会限制为正常的停止运行状态

重启docker服务后又回重复出现上面的错误

其中docker的一些命令也不能使用,如docker ps,docker info之类的,报错如下:

FATA[0000] Cannot connect to the Docker daemon. Is 'docker -d' running on this host?

看来是docker的守护进程没起来,而关于docker进程没起来的原因可能会有很多,比如

模块没加载,系统内核版本过低,硬盘空间不足等等

百度搜了一圈,国内大多都是抄来抄去,大多雷同,谷歌了一番,英文不太好,也没找到很合适的方案

如:

官方的一篇issue中有关于上面几种可能的原因中的一些解决方案

https://github.com/docker/docker/issues/6325

修改kernel内核添加修改CONFIG_DM_THIN_PROVISIONING=y

回顾下事件过程:

由于我这次docker挂掉起不来是因为docker容器目录磁盘空间爆满后的一些操作造成的,所以我还是优先考虑空间不足的问题:

docker ps  #查看容器ID

docker stop id  #停止容器

docker rm id    #删除容器

然后就卡死了,系统重启后,docker无法启动

解决方法:

rm -rf /var/lib/docker/*   #(记得备份重要数据)

哈哈 突然发现是如此的简单,前面都成扯淡的了…

cat xxx.tar.gz | docker import – name:tag

稍等片刻,成功部署…

2015-8-12更:

关于Docker停机扩容POOL空间:http://www.tuicool.com/articles/63EjyaV

分类: Docker容器技术 标签:

Docker搭建本地私有仓库

2016年10月28日 评论已被关闭

Docker搭建本地私有仓库

 http://www.cnblogs.com/xcloudbiz/articles/5500578.html

原文链接

和Mavan的管理一样,Dockers不仅提供了一个中央仓库,同时也允许我们使用registry搭建本地私有仓库。使用私有仓库有许多优点:

一、节省网络带宽,针对于每个镜像不用每个人都去中央仓库上面去下载,只需要从私有仓库中下载即可;

二、提供镜像资源利用,针对于公司内部使用的镜像,推送到本地的私有仓库中,以供公司内部相关人员使用。

接下来我们就大致说一下如何在本地搭建私有仓库。

环境准备

环境:两个装有Docker的Ubuntu虚拟机
虚拟机一:192.168.112.132 用户开发机
虚拟机二:192.168.112.136 用作私有仓库

此处我们准备了两个虚拟机,分别都安装了Docker,其中132机器用作开发机,136机器用作registry私有仓库机器。环境准备好之后接下来我们就开始搭建私有镜像仓库。

搭建私有仓库

首先在136机器上下载registry镜像

  1. $ sudo docker pull registry

下载完之后我们通过该镜像启动一个容器

  1. $ sudo docker run -d -p 5000:5000 registry

默认情况下,会将仓库存放于容器的/tmp/registry目录下,这样如果容器被删除,则存放于容器中的镜像也会丢失,所以我们一般情况下会指定本地一个目录挂载到容器的/tmp/registry下,如下:

  1. $ sudo docker run -d -p 5000:5000 -v /opt/data/registry:/tmp/registry registry


可以看到我们启动了一个容器,地址为:192.168.112.136:5000

接下来我们就要操作把一个本地镜像push到私有仓库中
在132机器下pull一个比较小的镜像来测试(此处使用的是busybox)

  1. $ sudo docker pull busybox

 

接下来修改一下该镜像的tag

  1. $ sudo docker tag busybox 192.168.112.136:5000/busybox


接下来把打了tag的镜像上传到私服

  1. $ sudo docker push 192.168.112.136:5000/busybox


可以看到push失败,具体结果如下:

2015/01/05 11:01:17 Error: Invalid registry endpoint https://192.168.112.136:5000/v1/: Get https://192.168.112.136:5000/v1/_ping: dial tcp 192.168.112.136:5000: connection refused. If this private registry supports only HTTP or HTTPS with an unknown CA certificate, please add `–insecure-registry 192.168.112.136:5000` to the daemon’s arguments. In the case of HTTPS, if you have access to the registry’s CA certificate, no need for the flag; simply place the CA certificate at /etc/docker/certs.d/192.168.112.136:5000/ca.crt

因为Docker从1.3.X之后默认docker registry使用的是https,所以当用docker pull命令下载远程镜像时,如果远程docker registry是非https的时候就会报上面的错误。

为了解决这个问题需要在启动docker server时增加启动参数
修改docker启动配置文件(此处是修改132机器的配置)Ubuntu下配置文件地址为:/etc/init/docker.conf
在其中增加–insecure-registry 192.168.112.136:5000如下所示:

  1. $ sudo vi /etc/init/docker.conf


修改完之后,重启Docker服务

  1. $ sudo restart docker


重启完之后我们再次运行推送命令,把本地镜像推送到私有服务器上

  1. $ sudo docker push 192.168.112.136:5000/busybox


可以看到镜像已经push到私有仓库中去了,接下来我们删除本地镜像,然后从私有仓库中pull下来该镜像

删除了本地镜像,然后我们从私有镜像仓库中下载该镜像

  1. $ sudo docker pull 192.168.112.136:5000/busybox


好了,到此本地搭建registry私有仓库就完结了,如有任何问题欢迎指正

不积跬步,无以至千里;不积小流,无以成江海.
分类: Docker容器技术 标签:

部署私有Docker Registry

2016年10月28日 评论已被关闭

部署私有Docker Registry

http://tonybai.com/2016/02/26/deploy-a-private-docker-registry/

安装部署一个私有的Docker Registry是引入、学习和使用Docker这门技术的必经之路之一。尤其是当Docker被所在组织接受,更多人、项目和产品开始接触和使用Docker时,存储和分发自制的Docker image便成了刚需。Docker Registry一如既往的继承了“Docker坑多”的特点,为此这里将自己搭建”各类”Registry过程中执行的步骤、遇到的问题记录下来,为己备忘,为他参考。

Docker在2015年推出了distribution项目,即Docker Registry 2。相比于old registry,Registry 2使用Go实现,在安全性、性能方面均有大幅改进。Registry设计了全新的Rest API,并且在image存储格式等方面不再兼容于old Registry。去年8月份,docker官方hub使用Registriy 2.1替代了原先的old Registry。如果你要与Registry2交互,你的Docker版本至少要是Docker 1.6。

Docker的开发者也一直在致力于改善Registry安装和使用的体验,通过提供官方Registry Image以及Docker Compose工具等来简化Registry的配置。不过在本文中,我们只是利用Docker以及Registry的官方Image来部署Registry,这样更便于全面了解Registry的部署配置细节。

Registry2在镜像存储方面不仅支持本地盘,还支持诸多主流第三方存储方案。通过分布式存储系统你还可以实现一个分布式Docker Registry服务。这里仅以本地盘以及single node registry2为例。

一、环境

这里还是复用以往文章中的Docker环境:

Docker Registry Server: 10.10.105.71 Ubuntu 14.04 3.16.0-57-generic;docker 1.9.1

其他两个工作Server:
10.10.105.72 Ubuntu 14.04 3.19.0-25-generic; docker 1.9.1
10.10.126.101 Ubuntu 12.04 3.16.7-013607-generic; docker 1.9.1

本次Registry使用当前最新stable版本:Registry 2.3.0。由于镜像采用本地磁盘存储,root分区较小,需要映射使用其他volume。

二、初次搭建

本以为Docker Registry的搭建是何其简单的,甚至简单到通过一行命令就可以完成的。比如我们在Registry Server上执行:

在~/dockerregistry下,执行:

$sudo docker run -d -p 5000:5000 -v `pwd`/data:/var/lib/registry --restart=always --name registry registry:2
Unable to find image 'registry:2' locally
2: Pulling from library/registry
f32095d4ba8a: Pull complete
9b607719a62a: Pull complete
973de4038269: Pull complete
2867140211c1: Pull complete
8da16446f5ca: Pull complete
fd8c38b8b68d: Pull complete
136640b01f02: Pull complete
e039ba1c0008: Pull complete
c457c689c328: Pull complete
Digest: sha256:339d702cf9a4b0aa665269cc36255ee7ce424412d56bee9ad8a247afe8c49ef1
Status: Downloaded newer image for registry:2
e9088ef901cb00546c59f89defa4625230f4b36b0a44b3713f38ab3d2a5a2b44

$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
registry            2                   c457c689c328        9 days ago          165.7 MB

$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED              STATUS              PORTS                    NAMES
e9088ef901cb        registry:2          "/bin/registry /etc/d"   About a minute ago   Up About a minute   0.0.0.0:5000->5000/tcp   registry

Registry container已经跑起来了,其启动日志可以通过:docker logs registry查看。

我们在71本地给busybox:latest打一个tag,并尝试将新tag下的image push到Registry中去:

$ docker tag busybox:latest 10.10.105.71:5000/tonybai/busybox:latest
$ docker images
REPOSITORY                          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
registry                            2                   c457c689c328        9 days ago          165.7 MB
busybox                             latest              65e4158d9625        9 days ago          1.114 MB
10.10.105.71:5000/tonybai/busybox   latest              65e4158d9625        9 days ago          1.114 MB
... ...

push到Registry中:

$ docker push 10.10.105.71:5000/tonybai/busybox
The push refers to a repository [10.10.105.71:5000/tonybai/busybox] (len: 1)
unable to ping registry endpoint https://10.10.105.71:5000/v0/
v2 ping attempt failed with error: Get https://10.10.105.71:5000/v2/: Tunnel or SSL Forbidden
 v1 ping attempt failed with error: Get https://10.10.105.71:5000/v1/_ping: Tunnel or SSL Forbidden

出错了!简单分析了一下,可能是71上docker daemon配置中加了http代理的缘故,导致无法ping通registry endpoint。于是在/etc/default/docker中注释掉export http_proxy=”xxx”的设置,并重启docker daemon。

再次尝试push:

$ docker push 10.10.105.71:5000/tonybai/busybox
The push refers to a repository [10.10.105.71:5000/tonybai/busybox] (len: 1)
unable to ping registry endpoint https://10.10.105.71:5000/v0/
v2 ping attempt failed with error: Get https://10.10.105.71:5000/v2/: tls: oversized record received with length 20527
 v1 ping attempt failed with error: Get https://10.10.105.71:5000/v1/_ping: tls: oversized record received with length 20527

虽然还是失败,但错误信息已有所不同了。这次看来连接是可以建立的,但client端通过https访问server端,似乎想tls通信,但这一过程并未完成。

在其他机器上尝试push image到registry也遇到了同样的错误输出,如下:

10.10.105.72:

$ docker push 10.10.105.71:5000/tonybai/ubuntu
The push refers to a repository [10.10.105.71:5000/tonybai/ubuntu] (len: 1)
unable to ping registry endpoint https://10.10.105.71:5000/v0/
v2 ping attempt failed with error: Get https://10.10.105.71:5000/v2/: tls: oversized record received with length 20527
 v1 ping attempt failed with error: Get https://10.10.105.71:5000/v1/_ping: tls: oversized record received with length 20527

从错误信息来看,client与Registry交互,默认将采用https访问,但我们在install Registry时并未配置指定任何tls相关的key和crt文件,https访问定然失败。要想弄清这个问题,只能查看Registry Manual

三、Insecure Registry

Registry的文档还是相对详尽的。在文档中,我们找到了Insecure Registry,即接收plain http访问的Registry的配置和使用方法,虽然这不是官方推荐的。

实际上对于我们内部网络而言,Insecure Registry基本能满足需求,部署过程也避免了secure registry的那些繁琐步骤,比如制作和部署证书等。

为了搭建一个Insecure Registry,我们需要先清理一下上面已经启动的Registry容器。

$ docker stop registry
registry
$ docker rm registry
registry

修改Registry server上的Docker daemon的配置,为DOCKER_OPTS增加–insecure-registry:

DOCKER_OPTS="--insecure-registry 10.10.105.71:5000 ....

重启Docker Daemon,启动Registry容器:

$ sudo service docker restart
docker stop/waiting
docker start/running, process 6712
$ sudo docker run -d -p 5000:5000 -v `pwd`/data:/var/lib/registry --restart=always --name registry registry:2
5966e92fce9c34705050e19368d19574e021a272ede1575385ef35ecf5cea019

尝试再次Push image:

$ docker push 10.10.105.71:5000/tonybai/busybox
The push refers to a repository [10.10.105.71:5000/tonybai/busybox] (len: 1)
65e4158d9625: Pushed
5506dda26018: Pushed
latest: digest: sha256:800f2d4558acd67f52262fbe170c9fc2e67efaa6f230a74b41b555e6fcca2892 size: 2739

这回push ok!

我们将本地的tag做untag处理,再从Registry pull相关image:

$ docker images
REPOSITORY                          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
registry                            2                   c457c689c328        9 days ago          165.7 MB
10.10.105.71:5000/tonybai/busybox   latest              65e4158d9625        9 days ago          1.114 MB
busybox                             latest              65e4158d9625        9 days ago          1.114 MB
ubuntu                              14.04               6cc0fc2a5ee3        5 weeks ago         187.9 MB

$ docker rmi 10.10.105.71:5000/tonybai/busybox
Untagged: 10.10.105.71:5000/tonybai/busybox:latest

$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
registry            2                   c457c689c328        9 days ago          165.7 MB
busybox             latest              65e4158d9625        9 days ago          1.114 MB
ubuntu              14.04               6cc0fc2a5ee3        5 weeks ago         187.9 MB

$ docker pull 10.10.105.71:5000/tonybai/busybox
Using default tag: latest
latest: Pulling from tonybai/busybox
Digest: sha256:800f2d4558acd67f52262fbe170c9fc2e67efaa6f230a74b41b555e6fcca2892
Status: Downloaded newer image for 10.10.105.71:5000/tonybai/busybox:latest

$ docker images
REPOSITORY                          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
registry                            2                   c457c689c328        9 days ago          165.7 MB
10.10.105.71:5000/tonybai/busybox   latest              65e4158d9625        9 days ago          1.114 MB
busybox                             latest              65e4158d9625        9 days ago          1.114 MB
ubuntu                              14.04               6cc0fc2a5ee3        5 weeks ago         187.9 MB

可以看到:Pull过程也很顺利。

在Private Registry2中查看或检索Repository或images,将不能用docker search

$ docker search 10.10.105.71:5000/tonybai/busybox/
Error response from daemon: Unexpected status code 404

但通过v2版本的API,我们可以实现相同目的:

$curl  http://10.10.105.71:5000/v2/_catalog
{"repositories":["tonybai/busybox"]}

$ curl  http://10.10.105.71:5000/v2/tonybai/busybox/tags/list
{"name":"tonybai/busybox","tags":["latest"]}

在其他主机上,我们尝试pull busybox:

10.10.105.72:

$docker pull 10.10.105.71:5000/tonybai/busybox
Using default tag: latest
Error response from daemon: unable to ping registry endpoint https://10.10.105.71:5000/v0/
v2 ping attempt failed with error: Get https://10.10.105.71:5000/v2/: tls: oversized record received with length 20527
 v1 ping attempt failed with error: Get https://10.10.105.71:5000/v1/_ping: tls: oversized record received with length 20527

我们发现依旧不能pull和push!在Registry手册中讲到,如果采用insecure registry的模式,那么所有与Registry交互的主机上的Docker Daemon都要配置:–insecure-registry选项。

我们按照上面的配置方法,修改105.72上的/etc/default/docker,重启Docker daemon,再执行pull/push就会得到正确的结果:

$ sudo vi /etc/default/docker
$ sudo service docker restart
docker stop/waiting
docker start/running, process 10614
$ docker pull 10.10.105.71:5000/tonybai/busybox
Using default tag: latest
latest: Pulling from tonybai/busybox
5506dda26018: Pull complete
65e4158d9625: Pull complete
Digest: sha256:800f2d4558acd67f52262fbe170c9fc2e67efaa6f230a74b41b555e6fcca2892
Status: Downloaded newer image for 10.10.105.71:5000/tonybai/busybox:latest

$ docker images
REPOSITORY                          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
ubuntu                              14.04               36248ae4a9ac        8 days ago          187.9 MB
10.10.105.71:5000/tonybai/ubuntu    14.04               36248ae4a9ac        8 days ago          187.9 MB
10.10.105.71:5000/tonybai/busybox   latest              65e4158d9625        9 days ago          1.114 MB

$ docker push 10.10.105.71:5000/tonybai/ubuntu
The push refers to a repository [10.10.105.71:5000/tonybai/ubuntu] (len: 1)
36248ae4a9ac: Pushed
8ea5373bf5a6: Pushed
2e0188208e83: Pushed
e3c70beaa378: Pushed
14.04: digest: sha256:72e56686cb9fb38438f0fd68fecf02ef592ce2ef7069bbf97802d959d568c5cc size: 6781

四、Secure Registry

Docker官方是推荐你采用Secure Registry的工作模式的,即transport采用tls。这样我们就需要为Registry配置tls所需的key和crt文件了。

我们首先清理一下环境,将上面的Insecure Registry停掉并rm掉;将各台主机上Docker Daemon的DOCKER_OPTS配置中的–insecure-registry去掉,并重启Docker Daemon。

如果你拥有一个域名,域名下主机提供Registry服务,并且你拥有某知名CA签署的证书文件,那么你可以建立起一个Secure Registry。不过我这里没有现成的证书,只能使用自签署的证书。严格来讲,使用自签署的证书在Docker官方眼中依旧属于Insecure,不过这里只是借助自签署的证书来说明一下Secure Registry的部署步骤罢了。

1、制作自签署证书

如果你有知名CA签署的证书,那么这步可直接忽略。

$ openssl req -newkey rsa:2048 -nodes -sha256 -keyout certs/domain.key -x509 -days 365 -out certs/domain.crt
Generating a 2048 bit RSA private key
..............+++
............................................+++
writing new private key to 'certs/domain.key'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:CN
State or Province Name (full name) [Some-State]:Liaoning
Locality Name (eg, city) []:shenyang
Organization Name (eg, company) [Internet Widgits Pty Ltd]:foo
Organizational Unit Name (eg, section) []:bar
Common Name (e.g. server FQDN or YOUR name) []:mydockerhub.com
Email Address []:bigwhite.cn@gmail.com

2、启动Secure Registry

启动带证书的Registry:

$ docker run -d -p 5000:5000 --restart=always --name registry \
  -v `pwd`/data:/var/lib/registry \
  -v `pwd`/certs:/certs \
  -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt \
  -e REGISTRY_HTTP_TLS_KEY=/certs/domain.key \
  registry:2
35e8ce77dd455f2bd50854e4581cd52be8a137f4aaea717239b6d676c5ea5777

由于证书的CN是mydockerhub.com,我们需要修改一下/etc/hosts文件:

10.10.105.71 mydockerhub.com

重新为busybox制作一个tag:

$docker tag busybox:latest mydockerhub.com:5000/tonybai/busybox:latest

Push到Registry:

$ docker push mydockerhub.com:5000/tonybai/busybox
The push refers to a repository [mydockerhub.com:5000/tonybai/busybox] (len: 1)
unable to ping registry endpoint https://mydockerhub.com:5000/v0/
v2 ping attempt failed with error: Get https://mydockerhub.com:5000/v2/: x509: certificate signed by unknown authority
 v1 ping attempt failed with error: Get https://mydockerhub.com:5000/v1/_ping: x509: certificate signed by unknown authority

push失败了!从错误日志来看,docker client认为server传输过来的证书的签署方是一个unknown authority(未知的CA),因此验证失败。我们需要让docker client安装我们的CA证书:

$ sudo mkdir -p /etc/docker/certs.d/mydockerhub.com:5000
$ sudo cp certs/domain.crt /etc/docker/certs.d/mydockerhub.com:5000/ca.crt
$ sudo service docker restart //安装证书后,重启Docker Daemon

再执行Push,我们看到了成功的输出日志。由于data目录下之前已经被push了tonybai/busybox repository,因此提示“已存在”:

$docker push mydockerhub.com:5000/tonybai/busybox
The push refers to a repository [mydockerhub.com:5000/tonybai/busybox] (len: 1)
65e4158d9625: Image already exists
5506dda26018: Image already exists
latest: digest: sha256:800f2d4558acd67f52262fbe170c9fc2e67efaa6f230a74b41b555e6fcca2892 size: 2739

3、外部访问Registry

我们换其他机器试试访问这个secure registry。根据之前的要求,我们照猫画虎的修改一下hosts文件,安装ca.cert,去除–insecure-registry选项,并重启Docker daemon。之后尝试从registry pull image:

$ docker pull mydockerhub.com:5000/tonybai/busybox
Using default tag: latest
latest: Pulling from tonybai/busybox

Digest: sha256:800f2d4558acd67f52262fbe170c9fc2e67efaa6f230a74b41b555e6fcca2892
Status: Downloaded newer image for mydockerhub.com:5000/tonybai/busybox:latest

$ docker images
REPOSITORY                             TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
10.10.105.71:5000/tonybai/ubuntu       14.04               36248ae4a9ac        9 days ago          187.9 MB
ubuntu                                 14.04               36248ae4a9ac        9 days ago          187.9 MB
10.10.105.71:5000/tonybai/busybox      latest              65e4158d9625        9 days ago          1.114 MB
mydockerhub.com:5000/tonybai/busybox   latest              65e4158d9625        9 days ago          1.114 MB

这样来看,如果使用自签署的证书,那么所有要与Registry交互的Docker主机都需要安装mydockerhub.com的ca.crt(domain.crt)。但如果你使用知名CA,这一步也就可以忽略。

五、Registry的鉴权管理

Registry提供了一种基础的鉴权方式。我们通过下面步骤即可为Registry加上基础鉴权:

在Register server上,为Registry增加foo用户,密码foo123:(之前需要停掉已有的Registry,并删除之)

//生成鉴权密码文件
$ mkdir auth
$ docker run --entrypoint htpasswd registry:2 -Bbn foo foo123  > auth/htpasswd
$ ls auth
htpasswd

//启动带鉴权功能的Registry:
$ docker run -d -p 5000:5000 --restart=always --name registry \
   -v `pwd`/auth:/auth \
   -e "REGISTRY_AUTH=htpasswd" \
   -e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" \
   -e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd \
   -v `pwd`/data:/var/lib/registry \
   -v `pwd`/certs:/certs \
   -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt \
   -e REGISTRY_HTTP_TLS_KEY=/certs/domain.key \
   registry:2
199ad0b3591fb9613b21b1c96f017267f3c39661a7025d30df636c6805e7ab50

在105.72上,我们尝试push image到Registry:

$ docker push mydockerhub.com:5000/tonybai/busybox
The push refers to a repository [mydockerhub.com:5000/tonybai/busybox] (len: 1)
65e4158d9625: Image push failed
Head https://mydockerhub.com:5000/v2/tonybai/busybox/blobs/sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4: no basic auth credentials

错误信息提示:鉴权失败。

在72上执行docker login:

$docker login mydockerhub.com:5000
Username: foo
Password:
Email: bigwhite.cn@gmail.com
WARNING: login credentials saved in /home/baiming/.docker/config.json
Login Succeeded

login成功后,再行Push:

$ docker push mydockerhub.com:5000/tonybai/busybox
The push refers to a repository [mydockerhub.com:5000/tonybai/busybox] (len: 1)
65e4158d9625: Image already exists
5506dda26018: Image already exists
latest: digest: sha256:800f2d4558acd67f52262fbe170c9fc2e67efaa6f230a74b41b555e6fcca2892 size: 2739

Push ok!

六、Registry中images的管理

前面提到过,通过V2版Rest API可以查询Repository和images:

$ curl --cacert domain.crt  --basic --user foo:foo123 https://mydockerhub.com:5000/v2/_catalog
{"repositories":["tonybai/busybox","tonybai/ubuntu"]}

但如果要删除Registry中的Repository或某个tag的Image,目前v2还不支持,原因见Registry的roadmap中的说明

不过如果你的Registry的存储引擎使用的是本地盘,倒是有一些第三方脚本可供使用,比如:delete-docker-registry-image

七、小结

Registry2发布不到1年,目前还有许多问题待解决,就比如delete image的问题,相信在2.4以及后续版本这些问题会被逐个解决掉或能找到一个相对理想的方案。

© 2016, bigwhite. 版权所有.