唐抉的个人博客

Docker应用部署基础

字数统计: 6.8k阅读时长: 32 min
2022/12/06

Docker

容器简介

什么是Linux容器

Linux容器是与系统其他部分隔离开的一系列进程。它在另一个镜像中运行,并由该镜像提供支持进程所需的全部文件。容器提供的镜像包括了应用的所有依赖项,因此在开发到测试再到生产的过程中,容器都具有可移植性和一致性。

容器等同于虚拟化吗

容器不完全是虚拟化。虚拟化使得许多系统可同时在单个系统上运行,而容器可共享同一个操作系统的内核,将应用进程与系统其他部分隔离开。

这便意味着,即使是让多个操作系统在单个虚拟机监控程序上运行以实现虚拟化,也不能达到和使用容器同等的轻量级效果。Linux容器可从单个操作系统运行,在所有容器中共享该操作系统,因此应用和服务能够保持轻量级,并可以快速运行。

什么是Docker

IT软件中所说的Docker,是指容器化技术,用于支持创建和使用Linux容器。借助Docker,可将容器当作重量轻、模块化的虚拟机使用,同时还将获得高度的灵活性,从而实现对容器的高效创建、部署及复制,并能将其从一个环境顺利迁移至另一个环境。

Docker技术使用Linux内核和内核功能来分隔进行,以便各进程相互独立运行。

Docker的目标

Docker的主要目标是构建、运输、处处运行(Build, Ship and Run any App, Angwhere)

构建:做一个Docker镜像

运输:Docker pull

运行:启动一个容器

每个容器都有自己的文件系统rootfs

安装Docker

在Centos系统中,安装命令如下:

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
29
30
31
32
33
34
#查看当前的内核版本
[root@localhost admin]# uname -r
3.10.0-1160.el7.x86_64

#查看已安装的CentOS版本信息
[root@localhost admin]# cat /etc/redhat-release
CentOS Linux release 7.9.2009 (Core)

#安装需要的软件包,yum-util提供yum-config-manager功能,另两个是devicemapper驱动依赖
yum install -y yum-utils device-mapper-persistent-data lvm2

#设置yun源,下面两个都可用
#(中央仓库)
yum-config-manager --add-repo http://download.docker.com/linux/centos/docker-ce.repo
#(阿里仓库)
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

#查看可用的Docker版本
yum list docker-ce --showduplicates | sort -r
#选择一个Docker版本并安装
yum -y install docker-ce-18.03.1.ce

#启动Docker并设置开机自启
systemctl start docker
systemctl enable docker

#查看Docker相关信息来验证是否正确安装了Docker
docker version
#配置Docker镜像加速
vim /etc/docker/daemon.json
{"registry-mirrors":["https://registry.docker-cn.com"]
}
#启动第一个容器
docker run hello-world

Hello World

Docker允许在容器中运行应用程序,使用docker run命令来在容器中运行一个应用程序,输出Hello World如下:

1
2
3
4
[root@localhost admin]# docker run ubuntu:15.10 /bin/echo "Hello world"
Hello world
#其中ubuntu:15.10为所指定的要运行的镜像,Docker会首先从本地主机上查找镜像是否存在,若不存在,Dockwe就会从镜像仓库中下载公共镜像
# /bin/echo "Hello world"为在启动的容器里执行的命令

运行交互式的容器

通过Docker的两个参数-i -t,可以让Docker运行的容器实现交互式对话的能力:

1
2
3
4
5
6
7
8
9
10
11
12
13
[root@localhost admin]# docker run -i -t ubuntu:15.10 /bin/bash
root@7cf8cc6326f7:/#
#此时已经进入了一个ubuntu:15.10系统的容器
#查看当前系统的版本信息
root@7cf8cc6326f7:/# cat /proc/version
Linux version 3.10.0-1160.el7.x86_64 (mockbuild@kbuilder.bsys.centos.org) (gcc version 4.8.5 20150623 (Red Hat 4.8.5-44) (GCC) ) #1 SMP Mon Oct 19 16:18:59 UTC 2020
#查看当前目录下的文件列表
root@7cf8cc6326f7:/# ls
bin dev home lib64 mnt proc run srv tmp var
boot etc lib media opt root sbin sys usr
#可以通过运行exit命令或使用Ctrl+D来退出容器
root@7cf8cc6326f7:/# exit
exit

后台模式启动容器

使用以下命令可以创建一个以进程方式运行的容器:

1
2
3
[root@localhost admin]# docker run -d ubuntu:15.10 /bin/sh -c "while true; do echo hello world; sleep 1;done"
#输出的长字符串为容器的ID
a26fa474ed2743ad2413c5e9c828faafa141ab1ec11ba3ffaf424de658b785de

容器ID对每个容器来说都是唯一的,可以通过容器ID来查看对应的容器发生了什么。

另外打开一个终端,用docker ps查看容器是否进行:

1
2
3
4
5
6
7
8
9
10
11
[root@localhost admin]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
54539564169f ubuntu:15.10 "/bin/bash" 31 seconds ago Up 30 seconds nostalgic_jennings

#CONTAINER ID 为容器ID
#IMAGE 为使用的镜像
#COMMAND 为启动容器时运行的命令
#CREATED 为容器的创建时间
#STATUS 为容器状态
#PORTS 为容器的端口信息和使用的连接类型(tcp\udp)
#NAMES 为自动分配的容器名称

容器的状态有7种:

  • created(已创建)
  • restarting(重启中)
  • running或Up(运行中)
  • removing(迁移中)
  • paused(暂停)
  • exited(停止)
  • dead(死亡)

停止容器

使用docker stop命令可以使容器停止:

1
docker stop 需要停止的容器ID

Docker镜像管理

Docker镜像常用命令

根据镜像名称获取镜像centos:docker pull centos

查看当前主机镜像列表:docker image list

查找镜像:docker search 镜像名

导入镜像(docker-centos.tar.gz为镜像名):docker image load -i docker-centos.tar.gz

导出镜像centos:docker image save centos > docker-centos.tar.gz

删除镜像hello-world:docker rmi hello-world

删除镜像centos:docker image rm centos:latest

更新镜像docker run -t -i ubuntu:15.10 /bin/bash

查看镜像的详细信息:docker image inspect centos

使用Dockerfile构建镜像

当从docker镜像仓库中下载的镜像不能满足需求时,可以通过以下两种方式对镜像进行更改:

  • 从已经创建的容器中更新镜像,并提交这个镜像
  • 使用Dockerfile命令来创建一个新的镜像

首先,使用命令docker build 从零开始创建一个新的镜像,为此需要创建一个Dockerfile文件,其中包含一组指令来告诉Docker如何构建镜像

1
2
3
4
5
6
7
8
9
10
11
12
[root@localhost admin]# touch Dockerfile
[root@localhost admin]# vim Dockerfile
FROM centos:6.7
MAINTAINER Fisher "fisher@sudops.com"

RUN /bin/echo 'root:123456' |chpasswd
RUN useradd runoob
RUN /bin/echo 'runoob:123456' |chpasswd
RUN /bin/echo -e "LANG=\"en_US.UTF-8\"" >/etc/default/local
EXPOSE 22
EXPOSE 80
CMD /usr/sbin/sshd -D

每一个指令都会在镜像上创建一个新的层,每一个指令的前缀都必须是大写的。

dockerfile 命令详情如下:

  • FROM:镜像从那里来

  • MAINTAINER:镜像维护者信息

  • RUN:构建镜像执行的命令,每一次RUN都会构建一层

  • CMD:容器启动的命令,如果有多个则以最后一个为准,也可以为ENTRYPOINT提供参数

  • VOLUME:定义数据卷,如果没有定义则使用默认

  • USER:指定后续执行的用户组和用户

  • WORKDIR:切换当前执行的工作目录

  • HEALTHCHECH:健康检测指令

  • ARG:变量属性值,但不在容器内部起作用

  • EXPOSE:暴露端口

  • ENV:变量属性值,容器内部也会起作用

  • ADD:添加文件,如果是压缩文件也解压

  • COPY:添加文件,以复制的形式

  • ENTRYPOINT:容器进入时执行的命令

其中,FROM指令指定只用哪个镜像源,RUN指令告诉docker在镜像内执行命令安装了什么。然后便可以使用Dockerfile 文件通过docker build 命令来构建一个镜像。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[root@localhost admin]# docker build -t runoob/centos:6.7 .
Sending build context to Docker daemon 205.8MB
Step 1/9 : FROM centos:6.7
6.7: Pulling from library/centos
cbddbc0189a0: Pull complete
Digest: sha256:4c952fc7d30ed134109c769387313ab864711d1bd8b4660017f9d27243622df1
Status: Downloaded newer image for centos:6.7
---> 9f1de3c6ad53
Step 2/9 : MAINTAINER Fisher "fisher@sudops.com"
---> Running in 5eaef1ca03a8
Removing intermediate container 5eaef1ca03a8
---> fb3340e270e3
...
Step 9/9 : CMD /usr/sbin/sshd -D
---> Running in 5856113fd1c1
Removing intermediate container 5856113fd1c1
---> 461a6483b47b
Successfully built 461a6483b47b
Successfully tagged runoob/centos:6.7

#其中参数-t为指定要创建的目标镜像名
#参数.为Dockerfile文件所在目录,也可以指定Dockerfile的绝对路径

查看创建的镜像runoob/centos 是否已经存在:

1
2
3
4
5
6
7
8
9
10
[root@localhost admin]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
runoob/centos 6.7 461a6483b47b 12 minutes ago 191MB
nginx latest 88736fe82739 2 weeks ago 142MB
ubuntu latest a8780b506fa4 4 weeks ago 77.8MB
hello-world latest feb5d9fea6a5 14 months ago 13.3kB
centos latest 5d0da3dc9764 14 months ago 231MB
centos 6.7 9f1de3c6ad53 3 years ago 191MB
ubuntu 15.10 9b9cb95443b5 6 years ago 137MB
training/webapp latest 6fae60ef3446 7 years ago 349MB

现在可以使用新的镜像来创建容器:

1
2
3
[root@localhost admin]# docker run -t -i runoob/centos:6.7 /bin/bash
[root@c256ace5a3db /]# id runoob
uid=500(runoob) gid=500(runoob) groups=500(runoob)

可以看到新镜像已经包含创建的用户runoob。

设置镜像标签

使用docker tag 命令可以为镜像添加一个新的标签:

1
2
3
4
5
6
7
8
9
10
11
12
root@localhost admin]# docker tag 461a6483b47b runoob/centos:dev
[root@localhost admin]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
runoob/centos 6.7 461a6483b47b 21 minutes ago 191MB
runoob/centos dev 461a6483b47b 21 minutes ago 191MB
nginx latest 88736fe82739 2 weeks ago 142MB
ubuntu latest a8780b506fa4 4 weeks ago 77.8MB
hello-world latest feb5d9fea6a5 14 months ago 13.3kB
centos latest 5d0da3dc9764 14 months ago 231MB
centos 6.7 9f1de3c6ad53 3 years ago 191MB
ubuntu 15.10 9b9cb95443b5 6 years ago 137MB
training/webapp latest 6fae60ef3446 7 years ago 349MB

容器的日常管理

启动容器

最简单的运行一个容器:docker run nginx

使用ubuntu镜像启动一个容器,参数以命令行模式进入该容器:docker run -it ubuntu /bin/bash-it是指交互式终端)

快速启动容器:docker run centos:latest /usr/bin/sleep 20

注意:容器内的第一个进程必须一直处于运行的状态,否则这个容器,就会处于退出状态!

查看正在运行的容器:docker container ls

查看容器详细信息/id:docker container inspect 容器名称/id

启动已停止运行的容器

查看所有容器(包括未运行的):docker ps -a

启动一个已停止运行的容器:docker start 容器名称/id

自命名启动一个容器:docker run --name ubuntu-test ubuntu /bin/bash

让ubuntu-test容器在后台运行:docker run -itd --name ubuntu-test ubuntu /bin/bash

停止容器:docker stop 容器名称/id或者docker container kill 容器名称/id

重启停止的容器:docker restart 容器名称/id

进入容器

在使用-d参数时,容器启动后会进入后台。此时想要进入容器,可以通过以下指令进入:

  • docker attach 容器名称/id :此命令会退出容器终端,且会导致容器停止
  • docker exec -it 容器名称/id /bin/bash:(推荐使用此命令,此命令会退出容器终端,但不会导致容器的停止)

导入容器快照

可以使用docker import 从容器快照文件中再导入为镜像,如将快照文件ubuntu.tar导入到镜像test/ubuntu:v1中:

1
cat docker /ubuntu.tar | docker import - test/ubuntu:v1

也可以通过指定URL或某个目录来导入,如:

1
docker import http://example.com/exampleimage.tag example/imagerepo

删除容器

使用docker rm 命令可删除容器:

1
docker rm -f 容器名称/id

清理掉所有处于终止状态的容器:

1
docker container prune

删除所有容器:

1
docker rm -f `docker ps -a -q`

使用docker构建一个web应用程序

在dockers容器中运行一个Python Flask应用来运行一个web应用:

1
2
3
4
5
6
7
[root@localhost admin]# docker pull training/webapp
[root@localhost admin]# docker run -d -p 5000:5000 training/webapp python app.py

8294ae65cc7397df396f1846582d2c55896646996eab41a26f9be0c01f3270f8

#-d:让容器在后台运行
#-P:将容器内部使用的网络端口随机映射到使用的主机上

不同指定的映射方法:

参数 说明
-p hostPort:containerPort 端口映射 -p 8080:80
-p ip:hostPort:containerPort 配置监听地址 -p 10.0.0.100:8080:80
-p ip::containerPort 随机分配端口 -p 10.0.0.100::80
-p hostPort:containerPort:udp 指定协议 -p 8080:80:tcp
-p 81:80 –p 443:443 指定多个

此时使用docker ps来查看正在运行的容器,会发现多了端口信息:

1
2
3
[root@localhost admin]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8294ae65cc73 training/webapp "python app.py" 49 seconds ago Up 47 seconds 0.0.0.0:32768->5000/tcp hardcore_brown

从端口信息中可知,Docker开放了5000端口(默认Python Flask端口)映射到主机端口32768上,此时可以通过浏览器访问WEB应用:(路径为主机ip:32768端口)

可以通过参数-p来设置不一样的端口,如将容器内部的5000端口映射到本地主机的5000端口上:

1
2
3
4
5
6
[root@localhost admin]# docker run -d -p 5000:5000 training/webapp python app.py
743a62b49b70f9575690e2b85d4ea1eed94dd19fe9f6074f1d7069d977a2ecc8
[root@localhost admin]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
743a62b49b70 training/webapp "python app.py" 22 seconds ago Up 21 seconds 0.0.0.0:5000->5000/tcp infallible_allen
8294ae65cc73 training/webapp "python app.py" 10 minutes ago Up 10 minutes 0.0.0.0:32768->5000/tcp hardcore_brown

网络端口的快捷方式

使用docker port 可以查看指定(ID或名字)容器的某个确定端口映射到宿主机的端口号。

查看容器端口情况可用:docker port 容器名称/id,如:

1
2
3
4
[root@localhost admin]# docker port 743a62b49b70
5000/tcp -> 0.0.0.0:5000
[root@localhost admin]# docker port infallible_allen
5000/tcp -> 0.0.0.0:5000

查看WEB应用程序日志

查看容器内部的标准输出,可以查看端口信息和应用程序的访问日志:

1
2
3
4
[root@localhost admin]# docker logs -f 743a62b49b70
* Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
192.168.18.129 - - [06/Dec/2022 01:43:49] "GET / HTTP/1.1" 200 -
192.168.18.129 - - [06/Dec/2022 01:43:49] "GET /favicon.ico HTTP/1.1" 404 -

检查WEB应用程序

使用docker inspect来查看Docker的底层信息,它会返回一个JSON文件记录着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
[root@localhost admin]# docker inspect 743a62b49b70
[
{
"Id": "743a62b49b70f9575690e2b85d4ea1eed94dd19fe9f6074f1d7069d977a2ecc8",
"Created": "2022-12-06T01:42:44.255608149Z",
"Path": "python",
"Args": [
"app.py"
],
"State": {
"Status": "running",
"Running": true,
"Paused": false,
"Restarting": false,
"OOMKilled": false,
"Dead": false,
"Pid": 17733,
"ExitCode": 0,
"Error": "",
"StartedAt": "2022-12-06T01:42:45.331479678Z",
"FinishedAt": "0001-01-01T00:00:00Z"
},
......
]

停止WEB应用容器

1
2
[root@localhost admin]# docker stop 743a62b49b70
743a62b49b70

重启WEB应用容器

已经停止的容器可以使用命令docker start来启动:

1
2
3
4
5
6
[root@localhost admin]# docker start 743a62b49b70
743a62b49b70
[root@localhost admin]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
743a62b49b70 training/webapp "python app.py" 14 minutes ago Up 14 seconds 0.0.0.0:5000->5000/tcp infallible_allen
8294ae65cc73 training/webapp "python app.py" 24 minutes ago Up 24 minutes 0.0.0.0:32768->5000/tcp hardcore_brown

移除WEB应用容器

使用docker rm 命令来删除不需要的容器:

1
2
3
4
5
6
7
8
9
10
11
#删除容器时,容器必须是停止状态,否则会报以下错误
[root@localhost admin]# docker rm 743a62b49b70
Error response from daemon: You cannot remove a running container 743a62b49b70f9575690e2b85d4ea1eed94dd19fe9f6074f1d7069d977a2ecc8. Stop the container before attempting removal or force remove

t@localhost admin]# docker stop 743a62b49b70
743a62b49b70
[root@localhost admin]# docker rm 743a62b49b70
743a62b49b70
[root@localhost admin]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8294ae65cc73 training/webapp "python app.py" 26 minutes ago Up 26 minutes 0.0.0.0:32768->5000/tcp hardcore_brown

Docker数据卷的管理

挂载时创建卷

挂载卷:

1
2
3
4
[root@localhost admin]# docker run -d -p 80:80 -v /data:/usr/share/nginx/html nginx:latest
5f2530020849d15287b8bfd4dd2274945c0fd07078ab281a17e47bf2243ea113

#/usr/share/nginx/html为容器内站点目录

在宿主机写入数据,查看:

1
2
3
4
5
[root@localhost admin]# echo "http://www.nmtui.com" >/data/index.html
[root@localhost admin]# curl 192.168.18.129
http://www.nmtui.com

#192.168.18.129为宿主机的ip地址

设置共享卷,使用同一个卷启动一个新的容器:

1
2
3
4
[root@localhost admin]# docker run -d -p 8080:80 -v /data:/usr/share/nginx/html nginx:latest
ad8ef6db5021d356f6b56a62d6aaa584ad8be7b8c8cac73cc7bd08369acf41d4
[root@localhost admin]# curl 192.168.18.129:8080
http://www.nmtui.com

查看卷列表:

1
2
[root@localhost admin]# docker volume ls
DRIVER VOLUME NAME

创建卷后挂载

创建一个卷:

1
2
3
4
5
[root@localhost admin]# docker volume create
8bbaf77b6495bbc8e50e75dfbd945badc0fdd2d2aced2359dc8d97308fa08d92
[root@localhost admin]# docker volume ls
DRIVER VOLUME NAME
local 8bbaf77b6495bbc8e50e75dfbd945badc0fdd2d2aced2359dc8d97308fa08d92

指定卷名:

1
2
3
4
5
6
[root@localhost admin]# docker volume create --name clsn
clsn
[root@localhost admin]# docker volume ls
DRIVER VOLUME NAME
local 8bbaf77b6495bbc8e50e75dfbd945badc0fdd2d2aced2359dc8d97308fa08d92
local clsn

查看卷路径:

1
2
3
4
5
6
7
8
9
10
11
12
13
[root@localhost admin]# docker volume inspect clsn
[
{
"CreatedAt": "2022-12-06T00:50:33-08:00",
"Driver": "local",
"Labels": {},
"Mountpoint": "/var/lib/docker/volumes/clsn/_data",
"Name": "clsn",
"Options": {},
"Scope": "local"
}
]

使用卷创建:

1
2
3
4
5
6
[root@localhost admin]# docker run -d -p 9000:80 -v clsn:/usr/share/nginx/html nginx:latest
3d4e986ad050c199740ec6a2a4f38d0ba54ad78715cb72d21df396e0774f705f
#宿主机测试
[root@localhost admin]# echo 'blog.nmtui.com' >/var/lib/docker/volumes/clsn/_data/index.html
[root@localhost admin]# curl 192.168.18.129:9000
blog.nmtui.com

设置卷:

1
2
[root@localhost admin]# docker run -d -P --volumes-from 5f2530020849d15287b8bfd4dd2274945c0fd07078ab281a17e47bf2243ea113 nginx:latest
5e9a1d7ea93ea7b7fb2d6918cf1cc8805aff41daa21b7e7656be1a14b2662e94

查看使用的端口:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[root@localhost admin]# netstat -lntup
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:111 0.0.0.0:* LISTEN 595/rpcbind
tcp 0 0 192.168.122.1:53 0.0.0.0:* LISTEN 1320/dnsmasq
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1074/sshd
tcp 0 0 127.0.0.1:631 0.0.0.0:* LISTEN 1069/cupsd
tcp 0 0 127.0.0.1:25 0.0.0.0:* LISTEN 1352/master
tcp6 0 0 :::9000 :::* LISTEN 4270/docker-proxy
tcp6 0 0 :::111 :::* LISTEN 595/rpcbind
tcp6 0 0 :::8080 :::* LISTEN 3992/docker-proxy
tcp6 0 0 :::80 :::* LISTEN 3794/docker-proxy
tcp6 0 0 :::22 :::* LISTEN 1074/sshd
tcp6 0 0 ::1:631 :::* LISTEN 1069/cupsd
tcp6 0 0 ::1:25 :::* LISTEN 1352/master
tcp6 0 0 :::32768 :::* LISTEN 4388/docker-proxy
[root@localhost admin]# curl 192.168.18.129:32768
http://www.nmtui.com

手动将容器保存为镜像

启动一个centos6.8的镜像:

1
2
3
4
5
6
7
8
9
10
[root@localhost admin]# docker pull centos:6.8
[root@localhost admin]# docker run -it -p 1022:22 centos:6.8 /bin/bash
#在容器中安装sshd服务并修改系统密码
[root@4d61bc1e379d /]# yum install openssh-server -y
[root@4d61bc1e379d yum.repos.d]# echo "root:123456" |chpasswd
[root@4d61bc1e379d yum.repos.d]# /etc/init.d/sshd start
Generating SSH2 RSA host key: [ OK ]
Generating SSH1 RSA host key: [ OK ]
Generating SSH2 DSA host key: [ OK ]
Starting sshd: [ OK ]

启动完成后镜像进行ssh连接测试。

将容器提交为镜像:

1
2
[root@localhost admin]# docker commit 4d61bc1e379d centos6-ssh
sha256:9591270dae2dda5a96c94c47e291aae0eeab7599ada3cdf44701c4dfd72e8cee

使用新的镜像启动容器:

1
2
3
4
5
6
7
8
9
10
11
[root@localhost admin]# docker run -d -p 1122:22 centos6-ssh:latest /usr/sbin/sshd -D
0019e8bb73550eec2526a101a19814ec92dfb045dd2fdca4d36175005e63ba20
[root@localhost admin]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
0019e8bb7355 centos6-ssh:latest "/usr/sbin/sshd -D" 30 seconds ago Up 28 seconds 0.0.0.0:1122->22/tcp blissful_albattani
5e9a1d7ea93e nginx:latest "/docker-entrypoint.…" 2 hours ago Up 2 hours 0.0.0.0:32768->80/tcp xenodochial_kare
3d4e986ad050 nginx:latest "/docker-entrypoint.…" 2 hours ago Up 2 hours 0.0.0.0:9000->80/tcp vibrant_bhabha
ad8ef6db5021 nginx:latest "/docker-entrypoint.…" 2 hours ago Up 2 hours 0.0.0.0:8080->80/tcp awesome_jang
5f2530020849 nginx:latest "/docker-entrypoint.…" 2 hours ago Up 2 hours 0.0.0.0:80->80/tcp pensive_lumiere
76cf3b4dce49 ubuntu "/bin/bash" 8 hours ago Up 2 hours test2
58bbd5afb8bf ubuntu "/bin/bash" 8 hours ago Up 2 hours test1

进入到容器内,在容器里安装httpd服务:

1
2
[root@localhost admin]# docker exec -it 0019e8bb7355 /bin/bash
[root@0019e8bb7355 /]# yum install https -y

编写启动脚本:

1
2
3
4
5
6
[root@0019e8bb7355 /]# touch init.sh
[root@0019e8bb7355 /]# vi init.sh
#!/bin/bash
/etc/init.d/httpd start
/usr/sbin/sshd -D
[root@0019e8bb7355 /]# chmod +x init.sh

再次提交为新的镜像:

1
2
[root@localhost admin]# docker commit 0019e8bb7355 centos6-httpd
sha256:bd9f5c339cd8494f82b8cb06396446143824f819c59c9b971687f6a9193c718a

启动镜像,做好端口映射。并在浏览器中输入宿主机的ip地址进行测试访问:

1
2
3
[root@localhost admin]# docker run -d -p 1222:22 -p 88:88 centos6-httpd /init.sh
ecbc482a781975538e7c83763fb1573af811a5baf2bc7c93de176ebd5576f407

Docker容器连接

容器中可以运行一些网络应用,要让外部也可以访问这些应用,可以通过-p-P参数来指定端口映射。下面来实现通过端口连接到一个docker容器。

网络端口映射

使用-P绑定端口号后,使用docker ps可以看到容器端口5000绑定主机端口32770

1
2
3
4
5
[root@localhost admin]# docker run -d -p 32770:5000 training/webapp python app.py
14a465d810df4e782f84c4e1ade99fd56f5e237c3de80d8f0c77dc7c3e642696
[root@localhost admin]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
14a465d810df training/webapp "python app.py" 13 seconds ago Up 12 seconds 0.0.0.0:32770->5000/tcp angry_bassi

此外,还可以指定容器绑定的网络地址,如绑定127.0.0.1。

1
2
3
4
5
6
[root@localhost admin]# docker run -d -p 127.0.0.1:5001:5000 training/webapp python app.py
6124b2108719c7e18b8b35992a06b3f66036ad0b951744bcfc1ca17158c2b6e3
[root@localhost admin]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
6124b2108719 training/webapp "python app.py" 6 seconds ago Up 4 seconds 127.0.0.1:5001->5000/tcp keen_sammet
998f4a68770c training/webapp "python app.py" 4 minutes ago Up 4 minutes 0.0.0.0:32770->5000/tcp angry_bassi

这样便可以通过访问127.0.0.1:5001来访问容器的5000端口。这里默认都是绑定tcp端口,若要绑定UDP端口,则需要在端口后面加上/udp。

Docker容器互联

端口映射并不是唯一把docker连接到另一个容器的方法。docker有一个连接系统允许将多个容器连接在一起,共享连接信息。docker连接会创建一个父子关系,其中父容器可以看到子容器的信息。

容器命名

当要创建一个容器时,docker会自动对他进行命名,此外也可以使用--name标识来命名容器。

1
2
3
4
5
[root@localhost admin]# docker run -d -P --name runoob training/webapp python app.py
561d0028ee9aafe9d014340ad8cecbaf7f5e395f05432e3bd149c797e5dd5f13
[root@localhost admin]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
561d0028ee9a training/webapp "python app.py" 5 seconds ago Up 4 seconds 0.0.0.0:32771->5000/tcp runoob

--link参数连接容器

使用--link参数可以让容器之间安全的进行交互。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#创建一个新的数据库容器
[root@localhost admin]# docker run -d --name db training/postgres
Unable to find image 'training/postgres:latest' locally
latest: Pulling from training/postgres
a3ed95caeb02: Pull complete
6e71c809542e: Pull complete
2978d9af87ba: Pull complete
e1bca35b062f: Pull complete
500b6decf741: Pull complete
74b14ef2151f: Pull complete
7afd5ed3826e: Pull complete
3c69bb244f5e: Pull complete
d86f9ec5aedf: Pull complete
010fabf20157: Pull complete
Digest: sha256:a945dc6dcfbc8d009c3d972931608344b76c2870ce796da00a827bd50791907e
Status: Downloaded newer image for training/postgres:latest
ef6af7333f0af9302cc6935d48be863ba2db0fdb2c56eacf42c074aa62982b12
#然后创建一个新的web容器,并将他连接到db容器
[root@localhost admin]# docker run -d -P --name web --link db:db training/webapp python app.py
62888e6365e6551d2ceb6a6ddf7afcd39e861119f97b691b5116dba8e250e444
[root@localhost admin]#

此时db容器和web容器建立了互联关系。

--link参数的格式为--link name:alias,其中name是要链接的容器的名称,alias是这个连接的别名。

此时使用docker ps来查看容器的连接:

1
2
3
4
[root@localhost admin]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
62888e6365e6 training/webapp "python app.py" 4 minutes ago Up 4 minutes 0.0.0.0:32769->5000/tcp web
ef6af7333f0a training/postgres "su postgres -c '/us…" 7 minutes ago Up 7 minutes 5432/tcp db

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

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

  • 环境变量
  • 更新/etc/hosts文件

使用env命令来查看web容器的环境变量:

1
2
3
4
5
6
7
8
9
10
11
12
13
[root@localhost admin]# docker run --rm --name web2 --link db:db training/webapp env
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=1621d6dd6804
DB_PORT=tcp://172.17.0.2:5432
DB_PORT_5432_TCP=tcp://172.17.0.2:5432
DB_PORT_5432_TCP_ADDR=172.17.0.2
DB_PORT_5432_TCP_PORT=5432
DB_PORT_5432_TCP_PROTO=tcp
DB_NAME=/web2/db
DB_ENV_PG_VERSION=9.3
HOME=/root

#DB_开头的环境变量是供web容器连接db容器使用,前缀采用大写的连接别名

除了环境变量,Docker还添加host信息到父容器的/etc/hosts的文件。下面是父容器web的hosts文件:

1
2
3
4
5
6
7
8
9
10
11
12
[root@localhost admin]# docker run -t -i --rm --link db:db training/webapp /bin/bash
root@5f57b7dcc730:/opt/webapp# cat /etc/hosts
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.2 db ef6af7333f0a
172.17.0.4 5f57b7dcc730

#这里有2个host,第一个是web容器,web容器用id作为它的主机名。第二个是db容器的ip和主机名

在web容器中安装ping命令来测试是否跟db容器的连通:

1
2
3
4
5
6
root@5f57b7dcc730:/opt/webapp# apt-get install -yqq inetutils-ping
root@5f57b7dcc730:/opt/webapp# ping db
PING db (172.17.0.2): 56 data bytes
64 bytes from 172.17.0.2: icmp_seq=0 ttl=64 time=0.740 ms
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.089 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.075 ms

用ping来测试db容器,它会解析成172.17.0.2。

注意:官方的Ubuntu镜像默认没有安装ping,因此需要自行安装。

用户可以链接多个父容器到子容器,比如可以链接多个web到db容器上。

通过局域网络连接容器

由于 centos-ssh镜像已失效,因此,上述步骤更新为如下:

  • 创建名为t-net的网络

    1
    2
    3
    4
    5
    6
    7
    8
    [root@localhost admin]# docker network create -d bridge t-net 
    #其中-d表示网络类型,默认为bridge
    # 列出当前主机下所有网络
    [root@localhost admin]# docker network ls
    NETWORK ID NAME DRIVER SCOPE

    fee646ecddfa t-net bridge local
    ebdcdb71d1ba test-net bridge local

  • 打开一个终端,基于镜像centos:7启动容器app1,并将容器app1加入到网络t-net中,进入到容器app1里:

    1
    2
    3
    4
    5
    6
    7
    [root@localhost admin]# docker run -it --name app1 --network t-net centos:7
    Unable to find image 'centos:7' locally
    7: Pulling from library/centos
    2d473b07cdd5: Pull complete
    Digest: sha256:9d4bcbbb213dfd745b58be38b13b996ebb5ac315fe75711bd618426a630e0987
    Status: Downloaded newer image for centos:7
    [root@0ab7505ff23e /]#

  • 另外打开一个终端,基于镜像centos:7启动容器app2,并将容器app2也加入到网络t-net中,进入到容器app2里:

    1
    2
    [root@localhost admin]# docker run -it --name app2 --network t-net centos:7
    [root@6a32efbb3dbe /]#

  • 在容器app1中ping app2,在容器app2中ping app1(注意区分两个终端):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    [root@0ab7505ff23e /]# ping app2
    PING app2 (172.20.0.3) 56(84) bytes of data.
    64 bytes from app2.t-net (172.20.0.3): icmp_seq=1 ttl=64 time=0.045 ms
    64 bytes from app2.t-net (172.20.0.3): icmp_seq=2 ttl=64 time=0.064 ms
    ^C
    --- app2 ping statistics ---
    2 packets transmitted, 2 received, 0% packet loss, time 1000ms
    rtt min/avg/max/mdev = 0.045/0.054/0.064/0.012 ms

    [root@6a32efbb3dbe /]# ping app1
    PING app1 (172.20.0.2) 56(84) bytes of data.
    64 bytes from app1.t-net (172.20.0.2): icmp_seq=1 ttl=64 time=0.092 ms
    64 bytes from app1.t-net (172.20.0.2): icmp_seq=2 ttl=64 time=0.214 ms
    64 bytes from app1.t-net (172.20.0.2): icmp_seq=3 ttl=64 time=0.077 ms
    ^C
    --- app1 ping statistics ---
    3 packets transmitted, 3 received, 0% packet loss, time 2002ms
    rtt min/avg/max/mdev = 0.077/0.127/0.214/0.062 ms

  • 以上结果则表示0丢包,容器之间能够正常通讯。

Docker仓库管理

仓库是集中存放镜像的地方,目前Docker官方维护了一个公共仓库Docker Hub,大部分需求的镜像都可以通过在Docker Hub中直接找到。

登录和登出

若还没有Docker账号,可在 https://hub.docker.com 上免费注册一个。然后输入用户名和密码登录,登录成功后便可以从Docker hub上拉去自己账号下的全部镜像。

1
2
3
4
5
[root@localhost admin]# docker login
Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.
Username: tangmenjue
Password:
Login Succeeded

使用docker logout命令可以登出Docker hub。

拉取镜像

使用docker search命令可以查找官方仓库中的镜像,并利用docker pull命令将其下载到本地,例如要下载ubuntu镜像,操作如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[root@localhost admin]# docker search ubuntu
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
ubuntu Ubuntu is a Debian-based Linux operating sys… 15312 [OK]
websphere-liberty WebSphere Liberty multi-architecture images … 290 [OK]
ubuntu-upstart DEPRECATED, as is Upstart (find other proces… 112 [OK]
neurodebian NeuroDebian provides neuroscience research s… 97 [OK]
ubuntu/nginx Nginx, a high-performance reverse proxy & we… 69
open-liberty Open Liberty multi-architecture images based… 56 [OK]
ubuntu/apache2 Apache, a secure & extensible open-source HT… 50
ubuntu-debootstrap DEPRECATED; use "ubuntu" instead 49 [OK]
...
[root@localhost admin]# docker pull ubuntu
Using default tag: latest
latest: Pulling from library/ubuntu
7b1a6ab2e44d: Pull complete
Digest: sha256:626ffe58f6e7566e00254b638eb7e0f3b11d4da9675088f4781a50ae288f3322
Status: Downloaded newer image for ubuntu:latest

推送镜像

用户登录后,可以通过docker push命令将自己的镜像推送到Docker Hub,如:

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
29
30
31
32
33
34
#查看目前已有的镜像
root@localhost admin]# docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
centos latest 5d0da3dc9764 14 months ago 231MB
centos 6.7 9f1de3c6ad53 3 years ago 191MB
centos 6.8 82f3b5f3c58f 3 years ago 195MB
ubuntu 15.10 9b9cb95443b5 6 years ago 137MB
training/webapp latest 6fae60ef3446 7 years ago 349MB
training/postgres latest 6fa973bb3c26 8 years ago 365MB
#给ubuntu:15.10镜像打上标签,以下的tangmenjue都要替换成自己的Docker账号用户名
[root@localhost admin]# docker tag ubuntu:15.10 tangmenjue/ubuntu:15.10
#查看镜像的变化
[root@localhost admin]# docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
centos latest 5d0da3dc9764 14 months ago 231MB
centos 6.7 9f1de3c6ad53 3 years ago 191MB
centos 6.8 82f3b5f3c58f 3 years ago 195MB
ubuntu 15.10 9b9cb95443b5 6 years ago 137MB
tangmenjue/ubuntu 15.10 9b9cb95443b5 6 years ago 137MB
training/webapp latest 6fae60ef3446 7 years ago 349MB
training/postgres latest

#将自己的镜像推送到Docker Hub

[root@localhost admin]# docker push tangmenjue/ubuntu:15.10
The push refers to repository [docker.io/tangmenjue/ubuntu]
98d59071f692: Pushed
af288f00b8a7: Pushed
4b955941a4d0: Mounted from library/ubuntu
f121afdbbd5d: Pushed
15.10: digest: sha256:cc56b237986f2b9282f058cc7875ff5e9d0d9081934c8982ea1ec21288eeefeb size: 1150
[root@localhost admin]# docker search tangmenjue/ubuntu
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
tangmenjue/ubuntu 0
CATALOG
  1. 1. Docker
    1. 1.1. 容器简介
      1. 1.1.1. 什么是Linux容器
      2. 1.1.2. 容器等同于虚拟化吗
      3. 1.1.3. 什么是Docker
      4. 1.1.4. Docker的目标
    2. 1.2. 安装Docker
    3. 1.3. Hello World
      1. 1.3.1. 运行交互式的容器
      2. 1.3.2. 后台模式启动容器
      3. 1.3.3. 停止容器
    4. 1.4. Docker镜像管理
      1. 1.4.1. Docker镜像常用命令
      2. 1.4.2. 使用Dockerfile构建镜像
      3. 1.4.3. 设置镜像标签
    5. 1.5. 容器的日常管理
      1. 1.5.1. 启动容器
      2. 1.5.2. 启动已停止运行的容器
      3. 1.5.3. 进入容器
      4. 1.5.4. 导入容器快照
      5. 1.5.5. 删除容器
      6. 1.5.6. 使用docker构建一个web应用程序
      7. 1.5.7. 网络端口的快捷方式
      8. 1.5.8. 查看WEB应用程序日志
      9. 1.5.9. 检查WEB应用程序
      10. 1.5.10. 停止WEB应用容器
      11. 1.5.11. 重启WEB应用容器
      12. 1.5.12. 移除WEB应用容器
    6. 1.6. Docker数据卷的管理
      1. 1.6.1. 挂载时创建卷
      2. 1.6.2. 创建卷后挂载
      3. 1.6.3. 手动将容器保存为镜像
    7. 1.7. Docker容器连接
      1. 1.7.1. 网络端口映射
      2. 1.7.2. Docker容器互联
        1. 1.7.2.1. 容器命名
        2. 1.7.2.2. --link参数连接容器
        3. 1.7.2.3. 通过局域网络连接容器
    8. 1.8. Docker仓库管理
      1. 1.8.1. 登录和登出
      2. 1.8.2. 拉取镜像
      3. 1.8.3. 推送镜像