警告
本文最后更新于 2024-05-08,文中内容可能已过时。
Docker 是通过内核虚拟化技术(namespaces及cgroups等)来提供容器的资源隔离与安全保障等.由于docker通过操作系统层的虚拟化实现隔离,所以Dociker容器在运行时,不需要虚拟机(VM)额外的操作系统开销,提高资源利用率.
安装环境:
CentOS 7
docker: 17.09.0-ce
virtualbox: 5.1.30
1. 前言
docker 能干什么?
简化配置
代码流水线管理
环境一致性,提高开发效率
快速部署
…
2. 安装并启动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@00 ~] # yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo #导入docker源以便于安装最新版docker
[ root@00 ~] # yum install docker-ce -y
#########忽略安装过程#############
[ root@00 ~] # systemctl start docker #启动docker
● docker.service - Docker Application Container Engine
Loaded: loaded ( /usr/lib/systemd/system/docker.service; disabled; vendor preset: disabled)
Active: active ( running) since 三 2017-10-25 01:30:27 EDT; 4min 2s ago
Docs: https://docs.docker.com
Main PID: 2788 ( dockerd)
Memory: 21.3M
CGroup: /system.slice/docker.service
├─2788 /usr/bin/dockerd
└─2793 docker-containerd -l unix:///var/run/docker/libcontainerd/docker-containerd.sock --metrics-interval= 0 --start-time...
#############省略部分数据###################
[ root@00 ~] # ifconfig docker0 # docker 安装成功后默认创建一个docker0默认的网桥
docker0: flags = 4099<UP,BROADCAST,MULTICAST> mtu 1500
inet 172.17.0.1 netmask 255.255.0.0 broadcast 0.0.0.0
ether 02:42:72:b8:2a:55 txqueuelen 0 ( Ethernet)
RX packets 0 bytes 0 ( 0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 ( 0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
3. docker的使用
3.1. 镜像的增、删、查
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
35
36
37
38
39
40
41
# >>> 镜像查询
[ root@00 ~] # docker search centos #镜像搜索
INDEX NAME DESCRIPTION STARS OFFICIAL AUTOMATED
docker.io docker.io/centos The official build of CentOS. 3732 [ OK]
docker.io docker.io/ansible/centos7-ansible Ansible on Centos7 102 [ OK]
docker.io docker.io/jdeathe/centos-ssh CentOS-6 6.9 x86_64 / CentOS-7 7.4.1708 x8... 87 [ OK]
#------------------省略部分数据---------------------
# >>> 镜像下载
[ root@00 default] # docker pull docker.io/centos #镜像远程下载
#关于docker的加速器的配置,这个阿里云也有相关配置方法,具体不多说,下面是具体的配置文件和格式
# /etc/docker/daemon.json
#{
# "registry-mirrors": ["你的加速地址"]
#}
#
Using default tag: latest
Trying to pull repository docker.io/library/centos ...
latest: Pulling from docker.io/library/centos
d9aaf4d82f24: Pull complete
Digest: sha256:eba772bac22c86d7d6e72421b4700c3f894ab6e35475a34014ff8de74c10872e
# >>> 镜像查看
[ root@00 ~] # docker images #查看已安装镜像
REPOSITORY TAG IMAGE ID CREATED SIZE
docker.io/centos latest 196e0ce0c9fb 5 weeks ago 196.6 MB
# >>> 镜像导出
[ root@00 ~] # docker save -o centos.tar docker.io/centos # 导出镜像到本地
[ root@00 default] # docker rmi 196e0ce0c9fb # 镜像删除,使用镜像id进行删除
Untagged: docker.io/centos:latest
Untagged: docker.io/centos@sha256:eba772bac22c86d7d6e72421b4700c3f894ab6e35475a34014ff8de74c10872e
Deleted: sha256:196e0ce0c9fbb31da595b893dd39bc9fd4aa78a474bbdc21459a3ebe855b7768
Deleted: sha256:cf516324493c00941ac20020801553e87ed24c564fb3f269409ad138945948d4
# >>> 镜像导入
[ root@00 ~] # docker load --input centos.tar # 导入本的镜像或者docker load < centos.tar,关于docker命令,如果你是普通用户,只需要把你的用户加入到docker组当中就不需要sudo才可以执行命令了 sudo usermod -aG docker zabbix
cf516324493c: Loading layer [================================================== >] 205.2 MB/205.2 MB
Loaded image: docker.io/centos:latest
[ root@00 ~] # docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
docker.io/centos latest 196e0ce0c9fb 5 weeks ago 196.6 MB
3.2. 容器的添加、删除、登陆
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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
[ root@00 ~] # docker run centos /bin/echo 'hello word' # centos 为镜像名称,命令格式:docker run [参数] [镜像名称] [运行命令] (注:进程结束即代表容器结束)
hello word
############ 新建一个mydocker的容器,他的镜像是centos ########
############ --name:指定容器名称 -t:让docker分配一个伪终端,-i:表示打开标准输入 ########
[ root@00 ~] # docker run --name mydocker -t -i centos /bin/bash
[ root@8679d53c43c4 /] # ls #<=======注意看主机名已经改变
anaconda-post.log bin dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var
[ root@8679d53c43c4 /] # uname -a
Linux 8679d53c43c4 3.10.0-327.el7.x86_64 #1 SMP Thu Nov 19 22:10:57 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux
[ root@8679d53c43c4 /] # exit # 退出容器,则进程关闭,代表此容器已完全关闭
exit
[ root@00 ~] # docker ps -a # 查看已有容器
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8679d53c43c4 centos "/bin/bash" 16 minutes ago Exited ( 0) 5 seconds ago mydocker
5ae63174779d centos "/bin/echo 'hello wor" 23 minutes ago Exited ( 0) 23 minutes ago infallible_swirles
[ root@00 ~] # docker start mydocker # 重新启动容器,启动对象可以是id,也可以是名称
mydocker
[ root@00 ~] # docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
dbf1c20e7229 centos "/bin/echo 'hello wor" 23 minutes ago Exited ( 0) 23 minutes ago infallible_swirles
8679d53c43c4 centos "/bin/bash" 16 minutes ago Up 6 minutes mydocker
[ root@00 ~] # docker attach mydocker #重新连接到容器
[ root@8679d53c43c4 /] # #<=================
[ root@8679d53c43c4 /] #exit #<=================此处退出会直接退出容器
exit
[ root@00 ~] # docker start mydocker #重新启动
mydocker
##########如果你是真的认真看了前面的话,那么下面的东西应该就是你现在很想知道的############
##########第一种退出不关闭容器的方法#############
[ root@00 ~] # docker inspect -f "{{ .State.Pid }}" mydocker #获取mydocker进程的pid
6076
[ root@00 ~] # nsenter -t 6076 -m -u -i -n -p #nsenter 一个用于进入docker容器的一个命令,命令包含于包:util-linux中
######-t:指定pid -m、-u、-i、-p 表示进入不同的namespace,这个我还没有理解到是什么意思?
[ root@8679d53c43c4 /] # ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 09:44 ? 00:00:00 /bin/bash #容器执行的第一个进程
root 13 0 0 09:55 ? 00:00:00 -bash #nsenter 执行运行的bash,若退出,则退出的是此bash,运行的容器不会被关闭
root 30 13 0 09:58 ? 00:00:00 ps -ef
[ root@8679d53c43c4 /] # exit #<======================此处退出,不会关闭容器
logout
[ root@00 ~] # docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
dbf1c20e7229 centos "/bin/echo 'hello wor" 32 minutes ago Exited ( 0) 29 minutes ago infallible_swirles
8679d53c43c4 centos "/bin/bash" 52 minutes ago Up 15 minutes mydocker
[ root@00 ~] # vim docker_start.sh #创建docker 连接脚本 ,传入参数为名称或id
#!/bin/bash
# user nsenter to access docker
docker_in(){
NAME_ID = $1
PID = $( docker inspect -f "{{ .State.Pid }}" $NAME_ID )
nsenter -t $PID -m -u -i -n -p
}
docker_in $1
######第二种退出不关闭容器的方法#######
[ root@00 sh] # docker exec -it mydocker /bin/bash
[ root@ec3b3acd0611 /] # ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.0 11776 1664 ? Ss+ 05:39 0:00 /bin/bash
root 28 0.1 0.0 11776 1884 ? Ss 05:41 0:00 /bin/bash #<=======这一个是exec进入使用的bash
root 42 0.0 0.0 47448 1668 ? R+ 05:42 0:00 ps aux
[ root@ec3b3acd0611 /] # exit #<===========退出后不会关闭容器
exit
[ root@00 sh] # docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ec3b3acd0611 centos "/bin/bash" 5 minutes ago Up 4 minutes mydocker
f7d281e95ab7 centos "/bin/echo 'hello wor" 5 minutes ago Exited ( 0) 5 minutes ago clever_ritchie
[ root@00 sh] # docker exec mydocker ps -aux #docker exec 还有个功能,不进入容器执行命令
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.0 11776 1664 ? Ss+ 05:39 0:00 /bin/bash
root 55 0.0 0.0 47448 1664 ? Rs 05:45 0:00 ps -aux
[ root@00 sh] # docker rm f7d281e95ab7 # 删除容器,
f7d281e95ab7
[ root@00 sh] # docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ec3b3acd0611 centos "/bin/bash" 30 minutes ago Up 29 minutes mydocker
[ root@00 sh] # docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ec3b3acd0611 centos "/bin/bash" 30 minutes ago Up 29 minutes mydocker
f7d281e95ab7 centos "/bin/echo 'hello wor" 30 minutes ago Exited ( 0) 30 minutes ago clever_ritchie
[ root@00 sh] # docker rm f7d281e95ab7 #删除容器,(docker rm -f xxxxx:删除正在运行的容器)
f7d281e95ab7
[ root@00 sh] # docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ec3b3acd0611 centos "/bin/bash" 30 minutes ago Up 29 minutes mydocker
[ root@00 sh] # docker run --rm centos /bin/echo "hello" #临时在一个容器下执行,及执行后立即删除该容器
hello
[ root@00 sh] # docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ec3b3acd0611 centos "/bin/bash" About an hour ago Up About an hour mydocker
3.3. docker 的网络访问
网络访问类型:
3.3.1. 随即映射:随机指定端口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[ root@00 ~] # docker run --name mynginx -d -P nginx # -d:运行至后台 -P:随机指定端口
b9d892abd87e2df6a0b5ff5c79a82d4de885a22a97359f6cf0a38e25ed4b2665
[ root@00 ~] # docker ps -a #从进程中看到本地32768映射到主机容器的80端口
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b9d892abd87e nginx "nginx -g 'daemon ..." 25 seconds ago Up 24 seconds 0.0.0.0:32768->80/tcp mynginx
[ root@00 ~] # curl -I 127.0.0.1:32768 #请求地址,可以看到映射是成功的
HTTP/1.1 200 OK
Server: nginx/1.13.5
Date: Wed, 25 Oct 2017 11:59:45 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 08 Aug 2017 15:25:00 GMT
Connection: keep-alive
ETag: "5989d7cc-264"
Accept-Ranges: bytes
[ root@00 docker] # iptables -t nat -nvL|grep -i dnat
0 0 DNAT tcp -- !docker0 * 0.0.0.0/0 0.0.0.0/0 tcp dpt:32768 to:172.17.0.2:80
3.3.2. 指定映射:指定端口(IP)映射
1
2
3
4
5
6
7
8
9
10
[ root@00 ~] # docker run -d -p 81:80 --name nginx-81 nginx # -p(小写): 格式 ip:映射端口:容器端口,可指定多个映射,格式不变,多个-p 加映射
7937cd85d6af922defba7d39ed579ca517f33de2241ffea06ad19bec874064aa
[ root@00 ~] # docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7937cd85d6af nginx "nginx -g 'daemon ..." 31 seconds ago Up 30 seconds 0.0.0.0:81->80/tcp nginx-81
b9d892abd87e nginx "nginx -g 'daemon ..." 24 minutes ago Up 24 minutes 0.0.0.0:32768->80/tcp mynginx
# 映射到指定地址的指定端口 ip:hostPort:containerPort(-p 127.0.0.1:80:80)
# 映射到指定地址的任意端口 ip::containerPort(-p 127.0.0.1::0)
# 查看映射端口配置 docker port [dockername]
4. docker 数据管理
4.1. 数据卷
数据持久化配置,类似于linux下的mount,将容器内部目录挂载出来
1
2
3
4
[ root@00 ~] # docker run -d --name nginx1 -v /opt/sh/:/opt/sh/ nginx
77ea81965a73905cb677c0d93a337579e510f731e1de00d5e25c3462211cdf24
# -v src:dst<:ro> (-v 本地目录:映射目录:挂载方式(ro只读,默认rw)),挂载时,本地内容将覆盖容器内的内容
# 同样,-v的挂载也可以挂载文件,书写方式与挂载目录一样
4.2. 数据卷容器
用于多个容器之间的数据共享(其实就是个人感觉就是-v的升级版)
1
2
3
[ root@00 ~] # docker run -d --name nginx2 --volumes-from nginx1 nginx # --volumes-from跟的是需要挂载数据卷的容器名称
0bbd96890b19d7256dd9e668f0810d84fb45339fe05ed80a8e60ec3754fcefd5
# 挂载的数据卷容器停止时也可以实现数据共享
5. docker镜像构建与dockerfile
5.1. 手动构建
手动构建实际上就是在原有的官方基础镜像上安装自己所需要的东西
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[ root@00 ~] # docker run --name mynginx -it centos #先启动一个基础镜像
shaode #安装完成后可删除下载的缓存,可进一步缩小镜像的大小
[ root@2ab2639cdff2 /] # yum install nginx -y
Loaded plugins: fastestmirror, ovl
#----------------- 略过过程---------------------
[ root@2ab2639cdff2 /] # vi /etc/nginx/nginx.conf
daemon off; #在首行添加参数,让nginx运行到前台
[ root@00 ~] # docker commit -m "mynginx-test" 2ab2639cdff2 store/mynginx:v1 #提交仓库到本地镜像
sha256:3febcd06010093dacdde2de49822d63819ff41003d87e732416798bbc36bd685
[ root@00 ~] # docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
store/mynginx v1 3febcd060100 54 seconds ago 374MB #此镜像就修改后的镜像,可以看出镜像的大小与基础镜像centos不一样
centos latest 196e0ce0c9fb 4 months ago 197MB
nginx latest 1e5ab59102ce 3 months ago 108MB
[ root@00 ~] # docker run --name mynginxv1 -it store/mynginx:v1 nginx #store/mynginx:v1 一定加上TAG 否则他无法识别,将会在仓库中下载最后一个版本的
[ root@00 ~] #
5.2. Dockerfile
5.2.1. 一个简单的Dockerfile示例
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
[ root@00 ~] # cd /data/docker/Dockerfile
[ root@00 Dockerfile] # vim Dockerfile
# This Dockerfile
# 基础镜像
FROM centos
# 维护者
MAINTAINER blog.cx115.me
# 命令
RUN yum install -y epel-release
RUN yum install -y nginx && yum clean all
# 设置nginx运行到前台
RUN echo "daemon off;" >> /etc/nginx/nginx.conf
# 添加一个文件到一个目录下
ADD index.html /usr/share/nginx/html/index.html
# 对外开放80端口
EXPOSE 80
# 启动的命令
CMD [ "nginx" ]
[ root@00 Dockerfile] # echo "hello docker" >> index.html
5.2.2. 构建镜像
1
2
3
4
5
6
7
8
9
10
11
12
13
14
[ root@00 Dockerfile] # docker build -t nginx_f:v2 .
# 构建时候可以通过 --build-arg 来指定运行时候的环境变量
# docker build --build-arg "HTTP_PROXY=http://proxy.example.com:8080/" \
# --build-arg "HTTPS_PROXY=http://proxy.example.com:8080/" \
# --build-arg "NO_PROXY=localhost,127.0.0.1,.example.com" -t nginx_f:v2 .
Sending build context to Docker daemon 3.072kB
Step 1/8 : FROM centos
........
Successfully built 955bbe2213cc
Successfully tagged nginx_f:v2
[ root@00 Dockerfile] # docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx_f v2 955bbe2213cc 34 seconds ago 357MB
5.2.3. 启动镜像
1
2
3
4
5
6
7
[ root@00 Dockerfile] # docker run -d -p 88:80 nginx_f:v2
6e878cfe032e83091840ff8b7bb5142293131ff1b98e5c5b2bc80379b50a68e8
[ root@00 Dockerfile] # docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
6e878cfe032e nginx_f:v2 "nginx" 3 seconds ago Up 1 second 0.0.0.0:88->80/tcp dazzling_gauss
[ root@00 Dockerfile] # curl http://127.0.0.1:88
hello docker
5.2.4. Dockerfile 命令
https://www.cnblogs.com/dazhoushuoceshi/p/7066041.html
命令
描述
FROM
指定基础镜像(Dockerfile第一条命令必须是FROM)
MAINTAINER
指定信息维护者(描述)
RUN
需要让他执行什么命令
ADD
copy文件,会自动解压
WORKDIR
设置当前工作目录
VOLUME
设置卷,挂载主机目录
EXPOSE
指定对外的端口(镜像启动时-P随机映射的端口)
CMD
镜像启动后要做什么事情(启动命令,只能有一条,多条执行最后一条,镜像启动指定命令,则会覆盖这条)
ENTRYPOINT
与CMD命令一样,但如果镜像启动指定命令,则不会被覆盖
5.3. Dcokerfile 生产实践
一般先根据基础镜像构建适合自己的基础镜像(包含需要使用的一些工具等),再由自己构建的基础镜像构建实际需要使用的环境(如php、nginx等)。
Dockerfile在被修改时,镜像重新构建将从修改位置进行重建,因此把执行过程较长的放在前面可以让重新构建的时间减少很多。