Docker Build, Ship, Run; An open platform for distributed applications for developers and sysadmins

前言

下面5个链接是2014年的博客, 基于0.10.0, 当前是1.9.x (有些已经失效)

入门参考:

其实以前入门时, 有一个Interactive commandline tutorial, 我觉得挺好的, 但是现在没了.

那个时候docker官网的域名还是docker.io, 现在已经把docker.com拿下了, 变化还是挺大的.

实践:

基础

docker的分层镜像,支持devicemapper, aufs, btrfs。

目前本地1.11.0版本,默认是devicemapper

关于aufs,有两篇文章:

另外关于devicemapper,在同步系统时遇到一个问题:

rsync同步时/var/lib/docker/devicemapper/devicemapper/data这个文件显示100G,已经超出机器存储的总大小。

第一感觉就是类似esxi的精简置备(thin provisioning),网上搜了下,linux下叫sparse file

In computer science, a sparse file is a type of computer file that attempts to use file system space more efficiently when the file itself is mostly empty.

ls命令的-s参数可以看到实际使用大小:

$ ls -alsh /var/lib/docker/devicemapper/devicemapper
total 952M
4.0K drwx------ 2 root root 4.0K Jul  6 17:12 .
4.0K drwx------ 5 root root 4.0K Jul  6 19:14 ..
950M -rw------- 1 root root 100G Jul  6 22:25 data
2.0M -rw------- 1 root root 2.0G Jul  6 22:25 metadata

比如data文件,最前面是实际使用大小950M, 后面100G是最大分配的大小。但是rsync同步时是会按100G数据来同步的,并且这个也应该排除。

参考:

使用国内的 Docker Hub Mirror,编辑 /etc/docker/daemon.json,加上如使用 ustc:

{
    "registry-mirrors": ["https://docker.mirrors.ustc.edu.cn/"]
}

参考:

CMD 与 ENTRYPOINT 的区别

简单的说:

更详细可以看看这几篇,资源都不错:

遇到的问题

loop module

Gentoo下安装docker后启动报错, 看日志:

level=info msg="Listening for HTTP on unix (/var/run/docker.sock)"
level=error msg="There are no more loopback devices available."
level=fatal msg="Error starting daemon: error initializing graphdriver: loopback mounting failed"

原因是没有加载loop模块. 在/etc/conf.d/modules 中加入模块:

$ cat /etc/conf.d/modules
# You can define a list modules for a specific kernel version,
# a released kernel version, a main kernel version or just a list.
# The most specific versioned variable will take precedence.
#modules_2_6_23_gentoo_r5="ieee1394 ohci1394"
#modules_2_6_23="tun ieee1394"
#modules_2_6="tun"
#modules_2="ipv6"
#modules="ohci1394"

# You can give modules a different name when they load - the new name
# will also be used to pick arguments below.
#modules="dummy:dummy1"

# Give the modules some arguments if needed, per version if necessary.
# Again, the most specific versioned variable will take precedence.
#module_ieee1394_args="debug"
#module_ieee1394_args_2_6_23_gentoo_r5="debug2"
#module_ieee1394_args_2_6_23="debug3"
#module_ieee1394_args_2_6="debug4"
#module_ieee1394_args_2="debug5"

# You should consult your kernel documentation and configuration
# for a list of modules and their options.
modules="loop"

然后加载模块: modprobe loop

内核支持

一个是iptables nat表, 编译内核时忘了打开nat支持了, 导致docker启动不了(docker开启不修改iptables选项应该就没事了).

打开内核选项:

CONFIG_IP_NF_NAT

can't initialize iptables table nat'

安装完docker顺便发现有如下提示:

* Messages for package app-emulation/docker-1.10.0:

*   CONFIG_IP_NF_TARGET_MASQUERADE:     is not set when it should be.
*   CONFIG_CGROUP_HUGETLB:      is not set when it should be.
*   CONFIG_CGROUP_NET_PRIO:     is not set when it should be.
* Please check to make sure these options are set correctly.
* Failure to do so may cause unexpected problems.

就顺便一起重新编译内核了.

官方也提供了内核参数检查的脚本 docker/contrib/check-config.sh

docker hub 墙

可以通过配置HTTP_PROXY来解决:

HTTP_PROXY=http://127.1:8123 docker pull busybox

讨论帖:

1.11版本好像支持socks5代理了

针对registry的搜索

基于registry v1,列出全部的镜像:

$ curl http://localhost:5000/v1/search 2>/dev/null | jq '.results[].name'
"library/mongodb"
"library/elasticsearch"
"library/python"
"library/golang"

搜索某个镜像仓库,docker search指定仓库url:

$ docker search http://localhost:5000/python
NAME             DESCRIPTION   STARS     OFFICIAL   AUTOMATED
library/python                 0

列出某个镜像仓库的所有tags,参考官方registry api

$ curl http://localhost:5000/v1/repositories/library/python/tags 2>/dev/null | jq '.'
{
  "2.7": "7a7d87336a3328623e3fb332a8752b940097aec03e4d39804721bfda2fa2a08d"
}

官方Registry即:

curl https://registry.hub.docker.com/v1/repositories/ubuntu/tags 2>/dev/null | jq '.[].name'
"10.04"
"12.10"
"13.04"
...

docker stop vs. docker kill

具体看help和man

Docker Registry

docker registry 最开始是 v1 版本,参见我三年前写的博客 Docker 3 -- 自建Docker Registry,但是现在这个版本已经过时了,更多的是使用 v2 版本。

部署 docker registry 最简单的方法就是直接通过 docker 镜像来运行,docker hub 上的地址 registry。直接 pull 然后运行,不过运行前建议先看看 Dockerfile,比如 push 上去的镜像是放在 /var/lib/registry,所以建议将本地目录挂载到容器的这个目录,否则容器重启后数据就没了,具体的启动命令见:

docker run -d -p 5000:5000 --restart always --name registry \
        -v /home/registry/data:/var/lib/registry \
        registry:2

注意要指定为 v2 的版本。

推送到 registry 根据镜像的前缀确认推送的地址,所以需要给本地的镜像打一个额外的tag:

docker tag alpine:latest 127.0.0.1:5000/alpine

然后推送到本地的 registry。

可以通过如下查看目前有哪些镜像:

curl http://127.0.0.1:5000/v2/_catalog

关于认证,没有深入研究,直接使用了 registry 自带的 basic auth,参考 native basic auth

# 创建一个 auth 目录,生成简单认证的用户密码对
$ mkdir auth
$ docker run \
        --entrypoint htpasswd \
        registry:2 -Bbn testuser testpassword > auth/htpasswd

当然如果安装了 apache-tools 也可以直接使用 htpasswd 命令生成:

htpasswd -bBn testuser testpassword > auth/htpasswd

注意 -B 参数,使用 bcrypt 加密。

新的启动命令:

docker run -d -p 5000:5000 --restart always --name registry \
        -v /home/registry/data:/var/lib/registry \
        -v /home/registry/auth:/auth \
        -e "REGISTRY_AUTH=htpasswd" \
        -e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" \
        -e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd \
        registry:2

然后通过 docker login 来登录,登录会话保存到 ~/.docker/config.json 中,使用 docker logout 删除。通过 curl 访问:

curl -u testuser:testpassword --basic  http://127.0.0.1:5000/v2/_catalog

看到还有推荐 cesanta/docker_auth 这个仓库,未尝试。

Docker Compose

顾名思义,一个 Dockerfile 是针对于一个容器(服务),编排就是将项目所包含的一组服务组合起来,是更高一级的配置管理。

Docker Compose 安装参考官方 Install Compose,官方直接提供了编译好的二进制程序,放到 $PATH 下即可,或者通过 pip 安装。

下面这两篇都给出了一样的例子,通过 flask web 配合 redis 做一个简单的demo:

Docker Compose 会给里面定义的各服务做相应的 dns 记录,使一组服务之间方便互联。

其它参考:

一些链接