Docker

简介

Docker 是 dotCloud 最近几个月刚宣布的开源引擎,旨在提供一种应用程序的自动化部署解决方案,简单的说就是,在 Linux 系统上迅速创建一个容器(类似虚拟机)并在容器上部署和运行应用程序,并通过配置文件可以轻松实现应用程序的自动化安装、部署和升级,非常方便。因为使用了容器,所以可以很方便的把生产环境和开发环境分开,互不影响,这是 docker 最普遍的一个玩法。更多的玩法还有大规模 web 应用、数据库部署、持续部署、集群、测试环境、面向服务的云计算、虚拟桌面 VDI 等等。

Docker 使用 Go 语言编写,用 cgroup 实现资源隔离,容器技术采用 LXC. LXC 已经足够成熟,被多个主流 PaaS 服务商采用(比如 dotCloud),国内的一些互联网公司也在用(比如腾讯)。虽然都是企图解决自动化部署方面的问题,Docker 的解决方式有别于我们常提到的 Puppet/Chef,他们虽然走的是不同的路,但也可以拿来一起用。

安装 (ubuntu 12.04)

Due to a bug in LXC, Docker works best on the 3.8 kernel. Precise comes with a 3.2 kernel, so we need to upgrade it. The kernel you’ll install when following these steps comes with AUFS built in. We also include the generic headers to enable packages that depend on them, like ZFS and the VirtualBox guest additions.

sudo apt-get install python-software-properties
sudo apt-get install linux-image-generic-lts-raring linux-headers-generic-lts-raring
sudo reboot

添加docker源并安装docker

sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 36A1D7869245C8950F966E92D8576A8BA88D21E9
sudo sh -c "echo deb http://get.docker.io/ubuntu docker main > /etc/apt/sources.list.d/docker.list"
sudo apt-get update
sudo apt-get install lxc-docker

上面两步也可以替换成执行curl -s https://get.docker.io/ubuntu/ | sudo sh,更简单。

创建容器

首先从https://index.docker.io/下载一个预定义的镜像

sudo docker pull ubuntu

启动一个容器:

sudo docker run -i -t ubuntu /bin/bash

Starting a long-running worker process

# Start a very useful long-running process
JOB=$(sudo docker run -d ubuntu /bin/sh -c "while true; do echo Hello world; sleep 1; done")

# Collect the output of the job so far
sudo docker logs $JOB

# Kill the job
sudo docker kill $JOB

Bind a service on a TCP port

# Bind port 4444 of this container, and tell netcat to listen on it
JOB=$(sudo docker run -d -p 4444 ubuntu:12.10 /bin/nc -l 4444)

# Which public port is NATed to my container?
PORT=$(sudo docker port $JOB 4444 | awk -F: '{ print $2 }')

# Connect to the public port
echo hello world | nc 127.0.0.1 $PORT

# Verify that the network connection worked
echo "Daemon received: $(sudo docker logs $JOB)"

Committing (saving) a container state¶

Save your containers state to a container image, so the state can be re-used.

When you commit your container only the differences between the image the container was created from and the current state of the container will be stored (as a diff). See which images you already have using the docker images command.

# Commit your container to a new named image
sudo docker commit <container_id> <some_name>

# List your containers
sudo docker images

You now have a image state from which you can create new instances.

更多功能见http://docs.docker.io/

docker

  1. 什么是docker

Docker 是 Docker.Inc 公司开源的一个基于LXC技术之上构建的Container容器引擎, 源代码托管在 GitHub 上, 基于Go语言并遵从Apache2.0协议开源。 Docker在2014年6月召开DockerConf 2014技术大会吸引了IBM、Google、RedHat等业界知名公司的关注和技术支持,无论是从 GitHub 上的代码活跃度,还是Redhat宣布在RHEL7中正式支持Docker, 都给业界一个信号,这是一项创新型的技术解决方案。

docker的基本概念

①镜像:用来创建Docker容器的只读模板 ②容器:从镜像创建而来的运行实例,各个容器之间相互隔离 ③仓库:存放镜像的场所,如https://hub.docker.com/和http://www.dockerpool.com/

  1. 安装docker

对于centos7,直接执行yum -y install docker即可安装,安装完成后需要执行systemctl start docker来启动docker服务。

其他操作系统中的安装方法见https://docs.docker.com/installation/#installation

  1. 获取镜像

从Docker Hub仓库下载一个Ubuntu 12.04操作系统的镜像

$ sudo docker pull ubuntu:12.04
Pulling repository ubuntu
ab8e2728644c: Pulling dependent layers
511136ea3c5a: Download complete
5f0ffaa9455e: Download complete
a300658979be: Download complete
904483ae0c30: Download complete
ffdaafd1ca50: Download complete
d047ae21eeaf: Download complete

官方镜像比较慢的时候可以从其他仓库下载镜像,如

$ sudo docker pull www.dockerpool.com:5000/library/centos:centos7

查询本地已下载的镜像

$ sudo docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
ubuntu              12.04               0a51fcc173d8        2 days ago          111 MB
centos              httpd               9ad57da2b81c        6 weeks ago         336.5 MB
<none>              <none>              e01000c7bac8        6 weeks ago         336.5 MB
centos              latest              b157b77b1a65        8 weeks ago         243.7 MB

其中,镜像id唯一标识了镜像,TAG信息用来标记来自同一个仓库的不同镜像。例如ubuntu仓库中有多个镜像,通过TAG信息来区分发行版本,例如10.04、12.04、12.10、13.04、14.04等。创建容器时,如果不指定具体的标记,则默认使用latest标记信息。

除了从容器中下载已有镜像外,也可以根据已有镜像创建新的镜像。创建新镜像有多种方法:

①修改已有镜像后commit

$ sudo docker run -t -i ubuntu:12.04 /bin/bash
root@a439b6e894bb:/# apt-get update
root@a439b6e894bb:/# apt-get install nginx
root@a439b6e894bb:/# /etc/init.d/nginx start
root@a439b6e894bb:/# exit
$ sudo docker commit -m 'add ngnix' -a 'feisky' a439b6e894bb ubuntu:nginx
0a693112c443ce4fb21bc57a26d67f0648b9415e052f929be7e06701f5f3ca2d
$ sudo docker images
REPOSITORY                               TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
ubuntu                                   nginx               0a693112c443        9 seconds ago       153.1 MB
ubuntu                                   12.04               0a51fcc173d8        2 days ago          111 MB

②用dockerfile来创建镜像

首先创建一个Dockerfile:

$ cat Dockerfile 

# yet another ngnix
FROM ubuntu:12.04
MAINTAINER feisky <feisky@root>
RUN apt-get update
RUN apt-get -y install nginx
# put my local site to /var/www
ADD index.html /var/www/html/
# expose httpd port
EXPOSE 80
# the command to run
CMD ["/usr/sbin/nginx"]

$ sudo docker build -t 'ubuntu:www' .

③导入已有镜像

要从本地文件系统导入一个镜像,可以使用openvz(容器虚拟化的先锋技术)的模板来创建: openvz的模板下载地址为http://openvz.org/Download/templates/precreated

$ sudo cat ubuntu-14.04-x86_64-minimal.tar.gz |docker import - ubuntu:14.04

④导入docker save保存的镜像

$ sudo docker save -o ubuntu_12.04.tar ubuntu:12.04
$ sudo docker load --input ubuntu_14.04.tar
$ sudo docker load < ubuntu_14.04.tar  #同上

⑤导入已保存的容器

保存一个容器的方法

$ sudo docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                    PORTS               NAMES
7691a814370e        ubuntu:14.04        "/bin/bash"         36 hours ago        Exited (0) 21 hours ago                       test
$ sudo docker export 7691a814370e > ubuntu.tar

重新作为镜像导入进来

$ cat ubuntu.tar | sudo docker import - test/buntu:v1.0

注:用户既可以使用docker load来导入镜像存储文件到本地镜像库,也可以使用docker import来导入一个容器快照到本地镜像库。这两者的区别在于容器快照文件将丢弃所有的历史记录和元数据信息(即仅保存容器当时的快照状态),而镜像存储文件将保存完整记录,体积也要大。此外,从容器快照文件导入时可以重新指定标签等元数据信息。

镜像制作好后,可以通过docker push命令,把自己创建的镜像上传到仓库中来共享 $ sudo docker push ubuntu

如果一个镜像不需要了,可以删除它: $ sudo docker rmi e01000c7bac8

  1. 容器管理

容器是独立运行的一个或一组应用,以及它们的运行态环境。

启动容器

下面的命令输出一个"Hello World",之后终止容器:

$ sudo docker run ubuntu:nginx /bin/echo 'hello world'
hello world

下面的命令则启动一个bash终端,可以让用户进行交互。 $ sudo docker run -t -i ubuntu:12.04 /bin/bash

其中,-t选项让Docker分配一个伪终端(pseudo-tty)并绑定到容器的标准输入上, -i则让容器的标准输入保持打开。

对于已经停止的容器,可以用start命令重新启动:

$ sudo docker start 7fb349365baf
7fb349365baf
$ sudo docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
7fb349365baf        ubuntu:nginx        /bin/bash           29 minutes ago      Up 6 seconds                            goofy_ritchie0

docker run的一些有用参数:

①-d:以守护进程形式运行容器

其他命令:

nsenter --target $PID --mount --uts --ipc --net --pid连接容器终端
docker attach连接容器终端
docker stop来终止一个运行中的容器
docker restart命令会将一个运行态的容器终止,然后再重新启动它
docker logs获取容器的输出信息
docker ps查看正在运行的容器
docker ps查看正在运行和已经停止的容器

注意:当多个窗口同时attach到同一个容器的时候,所有窗口都会同步显示。当某个窗口因命令阻塞时,其他窗口也无法执行操作了。

  1. 仓库管理

对于默认Docker Hub仓库,通过执行docker login命令来输入用户名、密码和邮箱来完成注册和登录。 注册成功后,本地用户目录的.dockercfg中将保存用户的认证信息。

可以通过sudo docker search centos来搜索镜像,通过sudo docker pull centos来下载镜像。

https://registry.hub.docker.com/builds/add/提供的自动构建功能对于需要经常升级程序的镜像比较有用,目前仅支持Github和BitBucket。

私有仓库的搭建

① $ sudo docker run -d -p 5000:5000 registry
② $ sudo pip install docker-registry
③ $ cp config/config_sample.yml config/config.yml
④ $ sudo gunicorn --access-logfile - --error-logfile - -k gevent -b 0.0.0.0:5000 -w 4 --max-requests 100 docker_registry.wsgi:application

如何向私有仓库上传镜像

$ sudo docker tag ba58 192.168.7.26:5000/test$ sudo docker push 192.168.7.26:5000/test

通过$ curl http://192.168.7.26:5000/v1/search可以查询私有仓库的镜像,通过sudo docker pull 192.168.7.26:5000/test可以下载私有仓库的镜像。

  1. 数据管理

创建一个web容器,并加载一个数据卷到容器的/webapp目录:

$ sudo docker run -d -P --name web -v /webapp training/webapp python app.py

挂载一个主机目录作为数据卷:

$ sudo docker run -d -P --name web -v /src/webapp:/opt/webapp training/webapp python app.py

Docker挂载数据卷的默认权限是读写,用户也可以通过:ro指定为只读:

$ sudo docker run -d -P --name web -v /src/webapp:/opt/webapp:ro
training/webapp python app.py

也可以挂载一个本地主机文件作为数据卷:

$ sudo docker run --rm -it -v ~/.bash_history:/.bash_history ubuntu /bin/bash ,注意这会导致报错误信息,最好还是直接挂载文件的父目录

如果你有一些持续更新的数据需要在容器之间共享,最好创建数据卷容器。数据卷容器,其实就是一个正常的容器,专门用来提供数据卷供其它容器挂载的:

$ sudo docker run -d -v /dbdata --name dbdata training/postgres echo Data-only container for postgres

然后,在其他容器中使用–volumes-from来挂载dbdata容器中的数据卷。

$ sudo docker run -d --volumes-from dbdata --name db1 training/postgres
$ sudo docker run -d --volumes-from dbdata --name db2 training/postgres
  1. 网络管理

当Docker启动时,会自动在主机上创建一个docker0虚拟网桥,实际上是Linux的一个bridge,可以理解为一个软件交换机。它会在挂载到它的网口之间进行转发。

同时,Docker随机分配一个本地未占用的私有网段(在RFC1918中定义)中的一个地址给docker0接口。比如典型的172.17.42.1,掩码为255.255.0.0。此后启动的容器内的网口也会自动分配一个同一网段.

① 端口映射: 使用docker port 来查看当前映射的端口配置

$ sudo docker run -P ... #随机映射一个49000~49900的端口到内部容器开放的网络端口
$ sudo docker run -d -p 5000:5000 #映射到指定端口
$ sudo docker run -d -p 127.0.0.1:5000:5000 #映射到指定HOST+端口
$ sudo docker run -d -p 127.0.0.1::5000 #映射到指定HOST,端口随机生成
$ sudo docker run -d -p 127.0.0.1:5000:5000/udp #映射到指定UDP端口

② 容器互联

启动容器时指定容器名称:

$ sudo docker run -d --name db training/postgres

根据名称连接db容器

$ sudo docker run -d -P --name web --link db:db training/webapp python app.py

注意:–link参数的格式为–link name:alias,其中name是要链接的容器的名称,alias是这个连接的别名;如果名称未知,可以通过下面的命令查询:

$ sudo docker inspect -f "{{ .Name }}" aed84ee21bde

Docker在两个互联的容器之间创建了一个安全隧道,而且不用映射它们的端口到宿主主机上。在启动db容器的时候并没有使用-p和-P标记,从而避免了暴露数据库端口到外部网络上。

Docker 通过2种方式为容器公开连接信息:

其一是环境变量:

$ sudo docker run --rm --name web2 --link db:db training/webapp env
. . .
DB_NAME=/web2/db
DB_PORT=tcp://172.17.0.5:5432
DB_PORT_5000_TCP=tcp://172.17.0.5:5432
DB_PORT_5000_TCP_PROTO=tcp
DB_PORT_5000_TCP_PORT=5432
DB_PORT_5000_TCP_ADDR=172.17.0.5
. . .

其二是hosts:

$ sudo docker run -t -i --rm --link db:db training/webapp /bin/bash
root@aed84ee21bde:/opt/webapp# cat /etc/hosts
172.17.0.7  aed84ee21bde
. . .
172.17.0.5  db

③ 其他选项

只有在Docker服务启动的时候才能配置:

-b BRIDGE or --bridge=BRIDGE --指定容器挂载的网桥
--bip=CIDR --定制docker0的掩码
-H SOCKET... or --host=SOCKET... --Docker服务端接收命令的通道
--icc=true|false --是否支持容器之间进行通信
--ip-forward=true|false --请看下文容器之间的通信
-iptables=true|false --禁止Docker添加iptables规则
--mtu=BYTES --容器网络中的MTU

既可以在启动服务时指定,也可以Docker容器启动(docker run)时候指定:

--dns=IP_ADDRESS... --使用指定的DNS服务器
--dns-search=DOMAIN... --指定DNS搜索域

只有在docker run执行时使用:

-h HOSTNAME or --hostname=HOSTNAME --配置容器主机名
--link=CONTAINER_NAME:ALIAS --添加到另一个容器的连接
--net=bridge|none|container:NAME_or_ID|host --配置容器的桥接模式
-p SPEC or --publish=SPEC --映射容器端口到宿主主机
-P or --publish-all=true|false --映射容器所有端口到宿主主机

Related Articles

comments powered by Disqus