Docker 学习.1 从零开始的 docker 部署

Docker 作为一种新兴的虚拟化容器部署方式,相较于传统虚拟化更为轻便,并且由于 docker 封装的方式,使其可以不受依赖的限制将应用运行在任何系统中。


Docker 是个划时代的开源项目,它彻底释放了计算虚拟化的威力,极大提高了应用的维护效率,降低了云计算应用开发的成本!使用 Docker,可以让应用的部署、测试和分发都变得前所未有的高效和轻松!

本文引用书籍 《Docker 从入门到实践》 下载链接


Docker 简介

Docker 最初是 dotCloud 公司创始人 Solomon Hykes 在法国期间发起的一个公司内部项目,它是基于 dotCloud 公司多年云服务技术的一次革新,并于 2013 年 3 月以 Apache 2.0 授权协议开源,主要项目代码在 GitHub 上进行维护。Docker 项目后来还加入了 Linux 基金会,并成立推动 开放容器联盟(OCI)。

Docker 自开源后受到广泛的关注和讨论,至今其 GitHub 项目已经超过 4 万 6 千个星标和一万多个 fork。甚至由于 Docker 项目的火爆,在 2013 年底,dotCloud 公司决定改名为 Docker。Docker 最初是在 Ubuntu 12.04 上开发实现的;Red Hat 则从 RHEL 6.5 开始对 Docker 进行支持;Google 也在其 PaaS 产品中广泛应用 Docker。

Docker 现在分为 CE 和 EE 两大版本。CE 即社区版(免费,支持周期 7 个月),EE 即企业版,强调安全,付费使用,支持周期 24 个月。

Docker CE 分为 stable, test, 和 nightly 三个更新频道。每六个月发布一个 stable 版本 (18.03, 18.09, 19.03…)。

较旧版本的 Docker 被称为 docker (docker-engine) ,其版本停止在 Docker 1.13.1 并且不再更新。现在大家经常说的 Docker 实际上为 Docker CE


Docker 基本概念

Docker 包括三个基本概念,镜像(Image)容器(Container)仓库(Repository)

Docker 镜像 是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。镜像不包含任何动态数据,其内容在构建之后也不会被改变。镜像的实际体现是由一组文件系统组成,或者说,由多层文件系统联合组成。镜像构建时,会一层层构建,前一层是后一层的基础。每一层构建完就不会再发生改变,后一层上的任何改变只发生在自己这一层,不会对上一层有任何的改变。

Docker 容器 的实质是进程,但与直接在宿主执行的进程不同,容器进程运行于属于自己的独立的 命名空间。因此容器可以拥有自己的 root 文件系统、自己的网络配置、自己的进程空间,甚至自己的用户 ID 空间。容器内的进程是运行在一个隔离的环境里,使用起来,就好像是在一个独立于宿主的系统下操作一样。这种特性使得容器封装的应用比直接在宿主运行更加安全。每一个容器运行时,是以镜像为基础层,在其上创建一个当前容器的存储层,我们可以称这个为容器运行时读写而准备的存储层为容器存储层。

Docker 仓库 是一个提供集中的存储、分发镜像的服务。一个 Docker Registry 中可以包含多个仓库(Repository);每个仓库可以包含多个标签(Tag);每个标签对应一个镜像。通常,一个仓库会包含同一个软件不同版本的镜像,而标签就常用于对应该软件的各个版本。我们可以通过 < 仓库名>:< 标签> 的格式来指定具体是这个软件哪个版本的镜像。如果不给出标签,将以 latest 作为默认标签。仓库名经常以 两段式路径 形式出现,比如 jwilder/nginx-proxy,前者往往意味着 Docker Registry 多用户环境下的用户名,后者则往往是对应的软件名。但这并非绝对,取决于所使用的具体 Docker Registry 的软件或服务。


Docker 安装

Docker 官方提供了各种环境下的 安装指南 本文只讲解 CentOS 如何安装 Docker CE


卸载旧版本

较旧版本的 Docker 被称为 dockerdocker-engine。使用以下命令卸载旧版本。

sudo yum remove docker docker-client docker-client-latest docker-common docker-latest docker-latest-logrotate docker-logrotate docker-selinux docker-engine-selinux docker-engine

您可以根据需要以不同方式安装 Docker CE:

  • 大多数用户使用 Docker 的仓库 安装 Docker CE,同时便于后期的管理和升级,这是推荐的方法。
  • 有些用户下载 RPM 软件包进行 手动安装 同时完全手动的进行后期管理和升级。这在例如无法互联网的隔离系统上安装 Docker 的情况下非常有用。
  • 在测试和开发环境中,一些用户选择使用自动 脚本 来安装 Docker。

CentOS 使用 yum 源安装

安装所需的包。yum-utils 提供了 yum-config-manager 安装源的方式。并且 devicemapper 存储驱动程序需要 device-mapper-persistent-data 和 lvm2
(CentOS/RHEL 在 Docker CE 18.09 和之后的版本中默认使用的是 overlay2 驱动)

sudo yum install -y yum-utils device-mapper-persistent-data lvm2

使用以下命令设置 Docker 源

sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo

(可选)使用以下命令设置国内 Docker 源。(中国科学技术大学)

sudo yum-config-manager --add-repo http://mirrors.ustc.edu.cn/docker-ce/linux/centos/docker-ce.repo
sed -i 's/download.docker.com/mirrors.ustc.edu.cn\/docker-ce/g' docker-ce.repo

更新 yum 软件源缓存,并安装 Docker CE。

sudo yum makecache fast
sudo yum install docker-ce

配置开机启动 Docker CE,并启动 Docker CE

sudo systemctl enable docker
sudo systemctl start docker

默认情况下,docker 命令会使用 Unix socket 与 Docker 引擎通讯。而只有 root 用户和 docker 组的用户才可以访问 Docker 引擎的 Unix socket。出于安全考虑,一般 Linux 系统上不会直接使用 root 用户。因此,更好地做法是将需要使用 docker 的用户加入 docker 用户组。

(可选)创建 docker 用户组

sudo groupadd docker

(可选)将当前用户加入 docker 组

sudo usermod -aG docker $USER

测试 Docker 运行(需退出当前终端并重新登录)

[[email protected] ~]# docker run hello-world

Unable to find image 'hello-world:latest' locally

latest: Pulling from library/hello-world
d1725b59e92d: Pull complete
Digest: sha256:0add3ace90ecb4adbf7777e9aacf18357296e799f81cabc9fde470971e499788
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
1. The Docker client contacted the Docker daemon.
2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
(amd64)
3. The Docker daemon created a new container from that image which runs the
executable that produces the output you are currently reading.
4. The Docker daemon streamed that output to the Docker client, which sent it
to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
$ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
https://hub.docker.com/

For more examples and ideas, visit:
https://docs.docker.com/get-started/

若能正常输出以上信息,则说明安装成功。


(可选)CentOS 运行 Docker 出现 net.bridge 警告

默认配置下,如果在 CentOS 使用 Docker CE 运行 docker info 看到下面的这些警告信息:

WARNING: bridge-nf-call-iptables is disabled
WARNING: bridge-nf-call-ip6tables is disabled

请添加内核配置参数以启用这些功能。

sudo tee -a /etc/sysctl.conf <<-EOF
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF

然后重新加载 sysctl.conf 即可

sudo sysctl -p

(可选)配置国内 Docker Hub 镜像加速器

在 /etc/docker/daemon.json 中写入如下内容(如果文件不存在请新建该文件)

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

之后重新启动 Docker 服务。

sudo systemctl daemon-reload
sudo systemctl restart docker

(可选)CentOS 运行 Docker 出现转发警告

默认配置下,如果在 CentOS 使用 Docker CE 创建新容器时看到下面的这些警告信息:

WARNING: IPv4 forwarding is disabled. Networking will not work.  

请添加内核配置参数以启用这些功能。

sudo tee -a /etc/sysctl.conf <<-EOF
net.ipv4.ip_forward = 1
EOF

然后重新加载 sysctl.conf 即可

sudo sysctl -p

Docker 运行


获取镜像

从 Docker 镜像仓库获取镜像的命令是 docker pull。其命令格式为:

docker pull [选项] [Docker Registry 地址 [: 端口号]/] 仓库名 [: 标签]
具体的选项可以通过 docker pull --help 命令看到,这里我们说一下镜像名称的格式。

Docker 镜像仓库地址:地址的格式一般是 < 域名/IP>[: 端口号]。默认地址是 Docker Hub。
仓库名:如之前所说,这里的仓库名是两段式名称,即 < 用户名>/< 软件名>。对于 Docker Hub,如果不给出用户名,则默认为 library,也就是官方镜像。

[[email protected] ~]# docker pull ubuntu:18.04

18.04: Pulling from library/ubuntu
bf5d46315322: Pull complete
9f13e0ac480c: Pull complete
e8988b5b3097: Pull complete
40af181810e7: Pull complete
e6f7c7e5c03e: Pull complete
Digest: sha256:147913621d9cdea08853f6ba9116c2e27a3ceffecf3b492983ae97c3d643fbbe
Status: Downloaded newer image for ubuntu:18.04

上面的命令中没有给出 Docker 镜像仓库地址,因此将会从 Docker Hub 获取镜像。而镜像名称是 ubuntu:18.04,因此将会获取官方镜像 library/ubuntu 仓库中标签为 18.04 的镜像。


运行容器

有了镜像后,我们就能够以这个镜像为基础启动并运行一个容器。以上面的 ubuntu:18.04 为例,如果我们打算启动里面的 bash 并且进行交互式操作的话,可以执行下面的命令。

[[email protected] ~]# docker run -it --rm ubuntu:18.04 bash

[email protected]:/# cat /etc/os-release

NAME="Ubuntu"
VERSION="18.04.1 LTS (Bionic Beaver)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 18.04.1 LTS"
VERSION_ID="18.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=bionic
UBUNTU_CODENAME=bionic

docker run 就是运行容器的命令,具体格式我们会在 容器 一节进行详细讲解,我们这里简要的说明一下上面用到的参数。

-it:这是两个参数,一个是 -i:交互式操作,一个是 -t 终端。我们这里打算进入 bash 执行一些命令并查看返回结果,因此我们需要交互式终端。
–rm:这个参数是说容器退出后随之将其删除。默认情况下,为了排障需求,退出的容器并不会立即删除,除非手动 docker rm。我们这里只是随便执行个命令,看看结果,不需要排障和保留结果,因此使用 –rm 可以避免浪费空间。
ubuntu:18.04:这是指用 ubuntu:18.04 镜像为基础来启动容器。
bash:放在镜像名后的是命令,这里我们希望有个交互式 Shell,因此用的是 bash。

进入容器后,我们可以在 Shell 下操作,执行任何所需的命令。这里,我们执行了 cat /etc/os-release,这是 Linux 常用的查看当前系统版本的命令,从返回的结果可以看到容器内是 Ubuntu 18.04.1 LTS 系统。

最后我们通过 exit 退出了这个容器。


查看镜像

要想查看已经下载下来的镜像,可以使用 docker image ls 命令。

[[email protected] ~]# docker image ls

REPOSITORY TAG IMAGE ID CREATED SIZE
redis latest 5f515359c7f8 5 days ago 183 MB
nginx latest 05a60462f8ba 5 days ago 181 MB
mongo 3.2 fe9198c04d62 5 days ago 342 MB
<none> <none> 00285df0df87 5 days ago 342 MB
ubuntu 18.04 f753707788c5 4 weeks ago 127 MB
ubuntu latest f753707788c5 4 weeks ago 127 MB
ubuntu 14.04 1e0c3dd64ccd 4 weeks ago 188 MB
列表包含了 仓库名、标签、镜像 ID、创建时间 以及 所占用的空间。

其中仓库名、标签在之前的基础概念章节已经介绍过了。镜像 ID 则是镜像的唯一标识,一个镜像可以对应多个标签。因此,在上面的例子中,我们可以看到 ubuntu:18.04 和 ubuntu:latest 拥有相同的 ID,因为它们对应的是同一个镜像。

注意,docker image ls 查看的所占用空间和在 Docker Hub 上看到的镜像大小不同。比如,ubuntu:18.04 镜像大小,在这里是 127 MB,但是在 Docker Hub 显示的却是 50 MB。这是因为 Docker Hub 中显示的体积是压缩后的体积。在镜像下载和上传过程中镜像是保持着压缩状态的,因此 Docker Hub 所显示的大小是网络传输中更关心的流量大小。而 docker image ls 显示的是镜像下载到本地后,展开的大小,准确说,是展开后的各层所占空间的总和,因为镜像到本地后,查看空间的时候,更关心的是本地磁盘空间占用的大小。

另外一个需要注意的问题是,docker image ls 列表中的镜像体积总和并非是所有镜像实际硬盘消耗。由于 Docker 镜像是多层存储结构,并且可以继承、复用,因此不同镜像可能会因为使用相同的基础镜像,从而拥有共同的层。由于 Docker 使用 Union FS,相同的层只需要保存一份即可,因此实际镜像硬盘占用空间很可能要比这个列表镜像大小的总和要小的多。

你可以通过以下命令来便捷的查看镜像、容器、数据卷所占用的空间。

[[email protected] ~]# docker system df

TYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images 24 0 1.992GB 1.992GB (100%)
Containers 1 0 62.82MB 62.82MB (100%)
Local Volumes 9 0 652.2MB 652.2MB (100%)
Build Cache 0B 0B

删除本地镜像

如果要删除本地的镜像,可以使用 docker image rm 命令,其格式为:

docker image rm [选项] < 镜像 1> [< 镜像 2> ...]

其中,< 镜像> 可以是 镜像短 ID、镜像长 ID、镜像名 或者 镜像摘要。如下例

[[email protected] ~]# docker image ls

REPOSITORY TAG IMAGE ID CREATED SIZE
centos latest 0584b3d2cf6d 3 weeks ago 196.5 MB
redis alpine 501ad78535f0 3 weeks ago 21.03 MB
docker latest cf693ec9b5c7 3 weeks ago 105.1 MB
nginx latest e43d811ce2f4 5 weeks ago 181.5 MB

我们可以用镜像的完整 ID,也称为 长 ID,来删除镜像。使用脚本的时候可能会用长 ID,但是人工输入就太累了,所以更多的时候是用 短 ID 来删除镜像。docker image ls 默认列出的就已经是短 ID 了,一般取前 3 个字符以上,只要足够区分于别的镜像就可以了。


Docker 管理


创建容器并运行

docker run [OPTION] [IMAGE NAME] [COMMAND]

-i 则让容器的标准输入保持打开。由于没有分配伪终端,界面没有我们熟悉的 Linux 命令提示符,但命令执行结果仍然可以返回。
-t 选项让 Docker 分配一个伪终端(pseudo-tty)并绑定到容器的标准输入上(常见用法为 it 参数同时使用)
-d 让容器在后台运行
-p 手动映射容器端口
-P 自动映射容器端口
-v 挂载主机目录到容器 (目录不存在则创建)
--mount 挂载主机目录到容器 (目录不存在则报错)
--name 设置容器实例名称
--restart 配置容器自动重启方式
--rm 容器退出后随之将其删除

查看容器信息

docker container ls

查看容器的输出信息

docker container log [container ID or NAMES]

对于容器的启动、停止、重启、删除

docker container start [container ID or NAMES]
docker container stop [container ID or NAMES]
docker container restart [container ID or NAMES]
docker container rm [container ID or NAMES]

进入后台运行的容器进程(A 方式)

docker attach [container ID or NAMES]

从这个 stdin 中 exit,会导致容器的停止

进入后台运行的容器进程(B 方式)

docker exec [container ID or NAMES]

-i 和 -t 参数等价于 docker run -it 的含义
从这个 stdin 中 exit,不会导致容器的停止。
点赞