docker入门
什么是docker
Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的镜像中,然后发布到任何流行的 Linux或Windows 机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口。
容器其实就是我们生活特别常见的物体,比如,盛水的杯子,装笔的笔筒,吃饭的碗。都是容器。那么docker容器存放的不过就是程序以及程序所依赖的环境
docker特性
一致性
一般情况下,开发人员的代码是在本地上开发测试的,它可能对于线上多多少少有一点不同。 可能在本地测试的时候没问题,推到线上就有问题。docker解决了这个问题,docker把程序和程序所依赖的环境打包成一个容器,在本地测试的时候没问题,推到线上也就不会有问题。这就是一致性
快速
没有虚拟化技术之前,电商站点在重大促销的时候,访问量比平常大几十倍,甚至几百倍的可能。 这时候我们需要提前把多余的服务器进行调试,配置,上线。来应对即将到来的活动。 这期间可能是痛苦的。 docker就免去了这一环节。 docker可以 将当前使用的服务可以直接打包推送对应的服务器上。启动和暂停更是一个docker命令即可。
隔离性
docker一个容器只运行一个进程以及其子进程,每个容器之间具有隔离性。互不干扰。
和传统vm技术不一样
docker相关名词
镜像
Docker镜像含有启动容器所需要的文件系统及其内容,因此,其用于创建并启动docker容器。
镜像分层构建
镜像采用分层构建机制,最底层是bootfs,上一层为rootfs
bootfs里面包含了kernel和BootLoader,在容器启动完成之后,会将其umount掉,以节省资源。 rootfs则是那些/etc,/proc等等根文件系统。 这两层在容器中都是只读的,不是可写的。
传统模式中,bootfs在启动之后,会将rootfs先设定为只读模式,等自身完全通过检查之后,在将其转为可写模式,等启动完毕之后,我们就可以在系统上写入数据。
但是docker中,并不是这样,它们都是只读的,而且是叠加到一起的。 这里采用了一种联合挂载的技术。
镜像在创建的时候,它可以有很多层,每一层都是只读的,只有在它被实例化成为容器的时候,容器位于它的最上层,实现了可写层。 例如下图:
联合挂载技术
传统的挂载方式,如果挂载的目录有数据的话,那么原目录的数据会隐藏起来。docker使用的是aufs,将分层镜像的文件同时都显示出来。docker的分层镜像,除了aufs,docker还支持btrfs, devicemapper和vfs等
写时复制
当 Docker 第一次启动一个容器时,初始的读写层是空的,当文件系统发生变化时,这些变化都会应用到这一层之上。比如,如果想修改一个文件,这个文件首先会从该读写层下面的只读层复制到该读写层。由此,该文件的只读版本依然存在于只读层,只是被读写层的该文件副本所隐藏。该机制则被称之为写时复制(Copy on write)。
容器
容器就是基于镜像生成的一个可写层。 是依赖于镜像的。
仓库
存放镜像的地方,有docker官方维护的docker hub。 有本地的镜像仓库。还有国内的阿里云等第三方仓库。 稍后安装的时候会再次介绍
使用docker
安装docker
以centos7为例,安装的时候,首先关掉firewalld,并且建议安装最新版。此处使用仓库安装。
官方安装步骤
(1)安装docker仓库
[root@localhost ~] yum install -y yum-utils
[root@localhost ~] yum-config-manager \
> --add-repo \
> https://download.docker.com/linux/centos/docker-ce.repo
(2)安装docker
[root@localhost ~] yum install docker-ce
(3)启动docker
[root@localhost ~] systemctl start docker
准备仓库
如果使用docker官方的仓库,速度相对来说比较慢,阿里云等提供来网络加速功能。
此处以阿里云为例、
[root@localhost ~]# cat /etc/docker/daemon.json
{
"registry-mirrors": ["https://YOURID.mirror.aliyuncs.com"]
}
[root@localhost ~]# systemctl daemon-reload
[root@localhost ~]# systemctl restart docker
安装镜像
镜像可以直接使用pull命令拉取。 不添加版本号时,默认拉取latest,最新版
[root@localhost ~]# docker pull busybox
Using default tag: latest #默认下载最新版
latest: Pulling from library/busybox
Digest: sha256:95cf004f559831017cdf4628aaf1bb30133677be8702a8c5f2994629f637a209
Status: Image is up to date for busybox:latest
docker.io/library/busybox:latest
#查看现在存在的镜像
[root@localhost ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
busybox latest 1c35c4412082 11 days ago 1.22MB
容器命令
docker run
有了镜像就可以启动容器。 使用docker run命令
参数 | 解释 |
---|---|
-t | 运行的时候去启动一个伪终端 |
–name STRING | 容器名字 |
-i | 交互式 |
–rm | 在停止的时候将容器删除,数据也随之消失 |
–network | 容器加入的网络 |
-d | 运行在后台 |
[root@localhost ~]# docker container run --name myimg --rm -it busybox
/ # ps
PID USER TIME COMMAND
1 root 0:00 sh
8 root 0:00 ps
使用docker container ps可以查看容器运行状态
[root@localhost ~]# docker container ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
72e02b8c1648 busybox "sh" About a minute ago Up About a minute myimg
一个容器运行一个进程。使用了--rm选项,在容器退出的时候,容器也会消失
/ # exit
[root@localhost ~]# docker container ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
容器的进程可以被命令行中的进程覆盖掉。例如httpd容器默认运行的是"httpd -D FOREGROUND"
[root@localhost ~]# docker container run --name web --rm -it httpd
AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 172.17.0.2. Set the 'ServerName' directive globally to suppress this message
AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 172.17.0.2. Set the 'ServerName' directive globally to suppress this message
[Sun Jun 14 18:12:55.632316 2020] [mpm_event:notice] [pid 1:tid 139766166733952] AH00489: Apache/2.4.43 (Unix) configured -- resuming normal operations
[Sun Jun 14 18:12:55.632794 2020] [core:notice] [pid 1:tid 139766166733952] AH00094: Command line: 'httpd -D FOREGROUND'
我们可以使用/bin/bash来覆盖掉它原本的进程,但是具有服务的容器都要运行在前台
[root@localhost ~]# docker container run --name web --rm -it httpd /bin/bash
root@2558c47151f0:/usr/local/apache2# ls
bin build cgi-bin conf error htdocs icons include logs modules
docker container exec
在容器中执行命令
[root@localhost ~]# docker container exec myimg ps
PID USER TIME COMMAND
1 root 0:00 sh
6 root 0:00 ps
docker container stats
查看容器内的进程对资源占用的情况
docker container attach
将剥离终端的容器再次回到前端
[root@localhost ~]# docker container run -d --name web -it busybox
# 使用-d明令将进程放到后端运行。不能和--rm同时使用
使用attach重新回到前端
[root@localhost ~]# docker attach web
/ # ls
bin dev etc home proc root sys tmp usr var
docker container commit
我们在原有的镜像上做了修改之后,希望以后用自己做的版本,那么我们就可以将镜像推送上去
参数 | 解释 |
---|---|
-a | 指明作者信息 |
-p | 暂停容器在提交 |
[root@localhost ~]# docker container commit -a "ydong@local.com" -p web ydong/mytest
sha256:a16eba970aa0976a0d48bfcf1a8caa58e1115f2eb4d3429f1a3f3ffb0744e1d6
[root@localhost ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ydong/mytest latest a16eba970aa0 About a minute ago 1.22MB
docker container push
将容器推送到网络上,默认推到docker官网。
首先需要 docker login 登录一下
[root@localhost ~]# 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: ydong07
Password:
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store
Login Succeeded
如果想要传上官网,需要将镜像的标签改成和docker官网一样的名字
[root@localhost ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ydong07/mytest latest a16eba970aa0 33 minutes ago 1.22MB
[root@localhost ~]# docker push ydong07/mytest
The push refers to repository [docker.io/ydong07/mytest]
2d12cbc270a9: Pushed
1be74353c3d0: Pushed
latest: digest: sha256:f717af0e25021b50ba5ec2d7cdcb70653089711298232c9d9ad1b0af38f25b78 size: 734
docker image tag
给镜像重新打标签
[root@localhost ~]# docker image tag ydong/mytest mytest/ydong
docker四种网络
docker提供了四种可用网络
桥网络
docker在启动的时候,会默认生成一个名叫docker0的桥,默认情况下,容器的ip地址都由docker0桥来分配,这就导致来只有宿主机可以访问到容器内的服务。
以httpd为例
1)启动一个容器提供httpd服务
[root@localhost ~]# docker run --name web -it --rm httpd
AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 172.17.0.2. Set the 'ServerName' directive globally to suppress this message
AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 172.17.0.2. Set the 'ServerName' directive globally to suppress this message
[Sun Jun 14 19:59:09.744044 2020] [mpm_event:notice] [pid 1:tid 140096873837696] AH00489: Apache/2.4.43 (Unix) configured -- resuming normal operations
[Sun Jun 14 19:59:09.744448 2020] [core:notice] [pid 1:tid 140096873837696] AH00094: Command line: 'httpd -D FOREGROUND'
2)宿主机访问
3)外网访问,是本机的80端口
docker在启动之后会生成一个虚拟的docker0桥网卡。 当容器运行起来之后,它负责分配地址。还有一个vethb69aca8
的网卡名称,它相当于一根线,将容器的内的网线直接插到了docker0上
[root@ydong ~]# brctl show
bridge name bridge id STP enabled interfaces
docker0 8000.02428d0f865b no vethb69aca8
host网络
共享主机网络,主机的网络是什么样,容器的网络就是什么样。 和宿主机共享一个网络
示例:
[root@ydong ~]# docker run --name mytest -it --network host --rm busybox
/ # ifconfig
docker0 Link encap:Ethernet HWaddr 02:42:8D:0F:86:5B
inet addr:172.17.0.1 Bcast:172.17.255.255 Mask:255.255.0.0
inet6 addr: fe80::42:8dff:fe0f:865b/64 Scope:Link
UP BROADCAST MULTICAST MTU:1500 Metric:1
RX packets:12 errors:0 dropped:0 overruns:0 frame:0
TX packets:26 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:1392 (1.3 KiB) TX bytes:3259 (3.1 KiB)
ens33 Link encap:Ethernet HWaddr 00:0C:29:05:AA:AF
inet addr:192.168.199.157 Bcast:192.168.199.255 Mask:255.255.255.0
inet6 addr: fe80::89eb:3179:7d38:d8e8/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:175060 errors:0 dropped:0 overruns:0 frame:0
TX packets:283769 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:18035448 (17.1 MiB) TX bytes:687690836 (655.8 MiB)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:64790 errors:0 dropped:0 overruns:0 frame:0
TX packets:64790 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:351471668 (335.1 MiB) TX bytes:351471668 (335.1 MiB)
共享桥
内核中有6种名称空间,分别是:NET,UTS,IPC,MOUNT,USER,PID。NET,UTS和IPC是可以共享出去的。 MOUNT,USER,PID是不能共享的。
- NET:提供网络隔离能力
- UTS:提供主机名隔离能力
- IPC:提供进程间通信隔离能力
- MOUNT:提供磁盘挂载点和文件系统的隔离能力
- USER:提供用户隔离能力
- PID:提供进程隔离能力
空网络
无需用到网络时,不分配给它网络
expose port
假如容器中有httpd服务需要外界来访问它,但是bridge网络只能宿主机访问,外界如果想访问的话,需要使用-p选项,意思是将容器内的端口映射到宿主机上的某个端口,并暴露出去。相当于创建了DNAT规则
1)容器中的端口映射到宿主机上的随机端口。
[root@ydong ~]# docker run --name web -it --rm -p 80 httpd:2.4.43-alpine
[root@ydong ~]# docker port web
80/tcp -> 0.0.0.0:32771
#容器中的80端口映射到宿主机的32771
2)容器中的端口映射到宿主机上的制定端口
[root@ydong ~]# docker run --name web -it --rm --network bridge -p 80:80 httpd:2.4.43-alpine
[root@ydong ~]# docker port web
80/tcp -> 0.0.0.0:80
# 将容器中的端口80映射到宿主机上的80端口
3)宿主机绑定固定地址和固定端口
[root@ydong ~]# docker run --name web -it --rm --network bridge -p 192.168.199.157:80:80 httpd:2.4.43-alpine
[root@ydong ~]# docker port web
80/tcp -> 192.168.199.157:80
#容器中的80端口映射到157宿主机上的80端口
4)宿主机绑定固定地址和随机端口
[root@ydong ~]# docker run --name web -it --rm --network bridge -p 192.168.199.157::80 httpd:2.4.43-alpine
[root@ydong ~]# docker port web
80/tcp -> 192.168.199.157:32768
docker volume
docker的数据都是放在容器内部的, 容器消失,数据也一起消失。 为了方便数据迁移,容器和容器之间共享数据。docker有一个功能叫存储卷。它可以将容器内的数据目录映射到宿主机上的某一处位置。这样容器消失,数据也不会消失
[root@ydong ~]# docker run --name web -it --rm -v /ydong/www/html:/usr/local/apache2/htdocs httpd:2.4.43-alpine
[root@ydong ~]# curl http://172.17.0.2
<h1>/ydong/www/html</h1>
容器之间还可以使用同一个存储卷
[root@ydong ~]# docker run --name web2 -it --rm --volumes-from web php:7.4.6-apache-buster /bin/bash
root@f59b59cb74cc:/var/www/html# cat /usr/local/apache2/htdocs/index.html
<h1>/ydong/www/html</h1>
#这是两个不同的容器,挂载点都是一样的。