一、Install Docker
要想让 Docker 良好运行起来,最好你的操作系统是 64 位的,内核版本不低于 3.8,所以最好直接使用 CentOS 7 系列的系统,默认内核版本就是 3.10 。当然你也可以使用 Debian 之类的系统。我这里就以 CentOS 7 为例了,具体各个系统 Docker 的相关安装方法这里不作介绍,具体安装参考官档。
由于 CentOS 6 的系统内核版本是 2.68 版本,其 user namespaces 隔离这一块还不支持,所以天然被排除在外了。直到 3.10 内核版本才对 user namespaces 隔离完全支持,所以应该使用 CentOS 7 来作为 Docker 运行环境。
Linux 内核从版本 2.4.19 开始陆续引入了 namespaces 的概念。其目的是将某个特定的全局系统资源(global system resource)通过抽象方法使得 namespaces 中的进程看起来拥有它们自己的隔离的全局系统资源实例。
Linux 内核中实现了六种 namespace,按照引入的先后顺序,列表如下:
namespace | 引入的相关内核版本 | 被隔离的全局系统资源 | 在容器语境下的隔离效果 |
---|---|---|---|
Mount namespaces | Linux 2.4.19 | 文件系统挂接点 | 每个容器能看到不同的文件系统层次结构 |
UTS namespaces | Linux 2.6.19 | nodename 和 domainname | 每个容器可以有自己的 hostname 和 domainame |
IPC namespaces | Linux 2.6.19 | 特定的进程间通信资源,包括System V IPC 和 POSIX message queues | 每个容器有其自己的 System V IPC 和 POSIX 消息队列文件系统,因此,只有在同一个 IPC namespace 的进程之间才能互相通信 |
PID namespaces | Linux 2.6.24 | 进程 ID 数字空间 (process ID number space) | 每个 PID namespace 中的进程可以有其独立的 PID; 每个容器可以有其 PID 为 1 的root 进程;也使得容器可以在不同的 host 之间迁移,因为 namespace 中的进程 ID 和 host 无关了。这也使得容器中的每个进程有两个PID:容器中的 PID 和 host 上的 PID。 |
Network namespaces | 始于Linux 2.6.24 完成于 Linux 2.6.29 | 网络相关的系统资源 | 每个容器用有其独立的网络设备,IP 地址,IP 路由表,/proc/net 目录,端口号等等。这也使得一个 host 上多个容器内的同一个应用都绑定到各自容器的 80 端口上。 |
User namespaces | 始于 Linux 2.6.23 完成于 Linux 3.8) | 用户和组 ID 空间 | 在 user namespace 中的进程的用户和组 ID 可以和在 host 上不同; 每个 container 可以有不同的 user 和 group id;一个 host 上的非特权用户可以成为 user namespace 中的特权用户; |
Linux namespaces 的概念说简单也简单,说复杂也复杂。简单来说,我们只要知道,处于某个 namespaces 中的进程,能看到独立的它自己的隔离的某些特定系统资源;复杂来说,可以去看看 Linux 内核中实现 namespaces 的原理,网络上也有大量的文档供参考,这里不再赘述。
另外,Docker 从 1.13.x 版本开始,版本分为企业版 EE 和社区版 CE,版本号也改为按照时间线来发布,比如 19.03 就是 2019 年 3 月,有点类似于 ubuntu 的版本发布方式。企业版自然会提供一些额外的服务,当然肯定也是收费的。
企业版说明
1. 系统版本
1 2 3 4 5 |
$ cat /etc/redhat-release CentOS Linux release 7.6.1810 (Core) $ uname -r 3.10.0-327.28.3.el7.x86_64 |
2. 安装 Docker
Docker 命令工具需要 root 权限才能工作,你可以将你的用户放入 docker 组来避免每次都要使用 sudo。
较旧版本的 Docker 被称为 docker 或 docker-engine。如果已安装这些,请卸载它们以及相关的依赖项。
1 2 3 4 5 6 7 8 |
$ sudo yum remove docker \ docker-client \ docker-client-latest \ docker-common \ docker-latest \ docker-latest-logrotate \ docker-logrotate \ docker-engine |
注意,卸载时会保留 /var/lib/docker/ 的内容,包括图像,容器,卷和网络。 Docker CE 包现在称为 docker-ce。
在新主机上首次安装 Docker CE 之前,需要设置 Docker repo。之后,你可以从 repo 安装和更新 Docker。
1 2 3 |
$ sudo yum-config-manager \ --add-repo \ https://download.docker.com/linux/centos/docker-ce.repo |
安装最新版本的 Docker CE 和 containerd。
1 |
$ sudo yum install docker-ce docker-ce-cli containerd.io |
列出并对你的 repo 仓库中可用的版本进行排序。此示例按版本号对结果进行排序,从最高到最低,并被截断:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
$ yum list docker-ce --showduplicates | sort -r docker-ce.x86_64 3:19.03.9-3.el7 docker-ce-stable docker-ce.x86_64 3:19.03.8-3.el7 docker-ce-stable docker-ce.x86_64 3:19.03.7-3.el7 docker-ce-stable docker-ce.x86_64 3:19.03.6-3.el7 docker-ce-stable docker-ce.x86_64 3:19.03.5-3.el7 docker-ce-stable docker-ce.x86_64 3:19.03.4-3.el7 docker-ce-stable docker-ce.x86_64 3:19.03.3-3.el7 docker-ce-stable docker-ce.x86_64 3:19.03.2-3.el7 docker-ce-stable docker-ce.x86_64 3:19.03.1-3.el7 docker-ce-stable docker-ce.x86_64 3:19.03.13-3.el7 docker-ce-stable docker-ce.x86_64 3:19.03.12-3.el7 docker-ce-stable docker-ce.x86_64 3:19.03.11-3.el7 docker-ce-stable docker-ce.x86_64 3:19.03.10-3.el7 docker-ce-stable docker-ce.x86_64 3:19.03.0-3.el7 docker-ce-stable |
返回的列表取决于启用的 repo 库,并且特定于你的 CentOS 版本(在此示例中以 .el7 后缀表示)。
通过其完全限定的包名称安装特定版本,包名称(docker-ce)加上从第一个冒号(:)开始的版本字符串(第2列),直到第一个连字符,用连字符( – )分隔。例如,docker-ce-19.03.13。
1 |
$ sudo yum install docker-ce-<VERSION_STRING> docker-ce-cli-<VERSION_STRING> containerd.io |
Docker 已安装但尚未启动,并且已创建 docker 组,但未向该组添加任何用户。 启动 Docker 服务。
1 2 |
$ sudo systemctl enable docker.service $ sudo systemctl start docker |
查看 Docker 版本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
$ sudo docker version Client: Docker Engine - Community Version: 19.03.13 API version: 1.40 Go version: go1.13.15 Git commit: 4484c46d9d Built: Wed Sep 16 17:03:45 2020 OS/Arch: linux/amd64 Experimental: false Server: Docker Engine - Community Engine: Version: 19.03.13 API version: 1.40 (minimum version 1.12) Go version: go1.13.15 Git commit: 4484c46d9d Built: Wed Sep 16 17:02:21 2020 OS/Arch: linux/amd64 Experimental: false containerd: Version: 1.3.7 GitCommit: 8fba4e9a7d01810a393d5d25a3621dc101981175 runc: Version: 1.0.0-rc10 GitCommit: dc9208a3303feef5b3839f4323d9beb36df0a9dd docker-init: Version: 0.18.0 GitCommit: fec3683 |
运行测试 Docker
1 |
$ docker run --rm hello-world |
此命令下载测试映像并在容器中运行它,运行成功会输出一些信息,然后退出。
如果 docker 运行容器报错:Error response from daemon: OCI runtime create failed.
你可能需要运行 yum update 把系统升级到 7.4+ 版本(记得重启系统),或者安装低版本的 Docker,Docker 与操作系统的版本依赖性特别强,在安装时务必要注意!
RHEL 7.2 is no longer supported and Docker does not test their release against unsupported versions. You need to upgrade your OS, preferably to 7.4, to resolve this issue.
I’ve seen a few people with similar issues in the past few days that resolved this same error message by upgrading their OS. Some of the older packages no longer work with newer docker releases. One of those problems is an outdated libseccomp: https://github.com/moby/moby/issues/35906
二、Docker 创建一个 WordPress 容器
Docker HUB ,Docker 镜像首页,包括官方镜像和其它公开镜像。这个公共 registry 上有你需要的几乎所有东西的镜像:Ubuntu、Fedora、Postgresql、MySQL、Jenkins、Elasticsearch、Redis 等等。Docker 开发人员在这个公共 registry 里维护着数个镜像,不过你能从上面拉取大量来自用户发布的自建镜像。
因为国情的原因,国内下载 Docker HUB 官方的相关镜像比较慢,可以使用阿里云镜像加速器,但需要有一个阿里云账号就可以获得一个专属加速器,比如 https://zjbap5fx.mirror.aliyuncs.com;至于加速器怎么使用,阿里云都有说明。另外可能你需要或想要一个私有的 registry(用于开发应用之类的容器),有好几个方式可以设置自己的私有 registry,当然你也可以买一个。
下面我们以搭建一个 WordPress 为例开始 Docker 之旅。
第一步:搜索镜像(search)
1 2 3 |
$ docker search wordpress NAME DESCRIPTION STARS OFFICIAL AUTOMATED wordpress The WordPress rich content management syst... 1329 [OK] |
第二步:下载镜像(pull)
从公共 Registry 下载一个镜像:
1 |
$ docker pull wordpress |
WordPress 启动还需要 MySQL,所以我们还需要下载一个 MySQL。
1 |
$ docker pull mysql |
第三步:查看自己的镜像(images)
1 2 3 4 5 6 7 |
$ docker images REPOSITORY TAG IMAGE ID CREATED SIZE wordpress latest 368db5c51bcd 4 days ago 420 MB mysql latest cf725f136fd2 4 days ago 383.4 MB nginx latest e43d811ce2f4 4 days ago 181.4 MB ubuntu latest f753707788c5 12 days ago 127.1 MB hello-world latest c54a2cc56cbb 3 months ago 1.848 kB |
第四步:启动一个 WordPress 容器(run)
* 需要先启动 MySQL 容器
1 2 |
$ docker run --name mysql_wordpress -e MYSQL_ROOT_PASSWORD=wordpress -d mysql 75648d50943e7529628002f42efd01124c8338449d25be1fb58be5be056d2c0b |
参数说明:
--name
:给此容器指定一个名称。
-e MYSQL_ROOT_PASSWORD
:指定环境变量参数,如MySQL的root用户密码设定。
-d
:表示丢在后台运行。
容器启动后,输出的是分配的 ID,因为是随机的,你的将有所不同。另外对于 mysql 容器还提供了很多变量,可以使用docker exec mysql env
查看。
* 然后启动 WordPress 容器
1 2 |
$ docker run --name docker_wordpress --link mysql_wordpress:mysql -p 8080:80 -d wordpress 189b414ce5111f373fd0ae96a6465e09430a0bef7c40da166ed52aea9cb6a577 |
WordPress 容器运行参数解释:
--name
:给此容器指定一个名称。
--link
:指定需要关联的 MySQL 容器,并指定一个别名,这里的别名必须为 mysql,不然环境变量的名称就会改变。
-p
:指定此容器的端口,默认是 80;这里映射为 8080 了。
-d
:表示丢在后台运行。
-e WORDPRESS_DB_USER
:指定的一些环境参数,缺省连接 DB 的用户为 “root”。
-e WORDPRESS_DB_PASSWORD
:指定的一些环境参数,缺省连接 root 用户的密码为连接 MySQL 容器的环境变量 MYSQL_ROOT_PASSWORD 的值。
-e WORDPRESS_DB_NAME
:指定的一些环境参数,缺省库为 “wordpress”。
还有一些不常用的,比如:
1 2 3 4 5 6 7 8 |
-e WORDPRESS_AUTH_KEY -e WORDPRESS_SECURE_AUTH_KEY -e WORDPRESS_LOGGED_IN_KEY -e WORDPRESS_NONCE_KEY -e WORDPRESS_AUTH_SALT -e WORDPRESS_SECURE_AUTH_SALT -e WORDPRESS_LOGGED_IN_SALT -e WORDPRESS_NONCE_SALT |
这些变量都是在 WordPress 这个镜像中定义好的,某个地方引用某个变量都是定义好的,所以这里只需要传入对应的值即可。这里可能会考虑,目标容器link到源容器时是怎么获取源容器的连接信息呢?这就涉及到容器间 link 的机制,具体博客有说明。
接下来就可以在浏览器中输入 http://localhost:8080 进行 wordpress 的配置了。
第五步:列出当前正在运行的 docker 容器(ps)
1 2 3 4 |
$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 189b414ce511 wordpress "docker-entrypoint.sh" About an hour ago Up About an hour 0.0.0.0:8080->80/tcp docker_wordpress 75648d50943e mysql "docker-entrypoint.sh" About an hour ago Up About an hour 3306/tcp mysql_wordpress |
列出当前系统所有的容器
1 |
$ docker ps -a |
第六步:进入到一个 docker 容器(exec)
1 2 |
$ docker exec -ti docker_wordpress /bin/bash root@189b414ce511:/var/www/html# |
三、Docker 创建一个 Ubuntu 容器
首先确认我本地是有 Ubuntu 镜像的。
1 2 3 |
$ docker images ubuntu REPOSITORY TAG IMAGE ID CREATED SIZE ubuntu latest f753707788c5 12 days ago 127.1 MB |
然后我们来创建一个 Ubuntu 容器。
1 2 3 |
$ docker run --rm -it ubuntu /bin/bash root@32cb81d2683d:/# echo "first docker container" first docker container |
参数解释:
run
:运行一个容器。
--rm
:告诉 Docker 一旦运行的进程退出就删除容器,这在进行测试时非常有用,可免除杂乱。
-ti
:告诉 Docker 启动后分配一个伪终端(-t,tty)并进入交互模式(-i,interactive),要配合 /bin/bash 一块使用,这样我们就可以和这个 Docker 容器进行交互了。这将进入到容器内,对于快速原型开发或尝试很有用,但不要在生产容器中使用。
ubuntu
:这是容器立足的镜像。
/bin/bash
:开启 Docker 后要运行的程序,因为我们以交互模式(-ti)启动,它将显示一个容器的提示符。
所以,上面这条指令翻译成人类的语言就是:请帮我启动一个容器,在容器里执行 /bin/bash,并且给我分配一个命令行终端跟这个容器交互。
在运行 run 命令时,你可指定链接、卷、端口、窗口名称(如果你没提供,Docker 将分配一个默认名称)等等。
Note
镜像 ubuntu 会有多个版本,通过指定 tag 来启动特定的版本
[image]:[tag]
。