Docker
Docker
是一个开源的应用容器引擎,基于Go
语言 并遵从Apache2.0
协议开源。
Docker 官网
:https://www.docker.com
Github Docker
源码:https://github.com/docker/docker-ce
概念
-
镜像 Image
镜像类似于虚拟机镜像,面向docker的只读模板,包含了文件系统
-
容器 Container
容器类似一个轻量级的沙箱,docker利用它运行隔离应用。容器是从镜像创建的应用实例,容器之间相互隔离。镜像本身是只读的,容器从镜像启动时,docker会在镜像最上层创建一个可写层,镜像保持不变。
-
仓库 Repository
类似于代码仓库,存放镜像文件的敌方。注册服务器(Registry)是存放仓库的地方。创建仓库后可以通过push命令上传到公有或私有仓库。
安装
CentOS 7
yum install -y yum-utils device-mapper-persistent-data lvm2
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
yum makecache
yum -y install docker-ce docker-ce-cli containerd.io
sudo systemctl restart docker
docker run hello-world
CentOS 8
dnf install -y yum-utils device-mapper-persistent-data lvm2
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
dnf makecache
dnf -y install docker-ce docker-ce-cli containerd.io
sudo systemctl restart docker
docker run hello-world
RockyLinux
dnf config-manager --add-repo=https://download.docker.com/linux/centos/docker-ce.repo
sudo dnf -y install docker-ce docker-ce-cli containerd.io docker-compose-plugin
sudo systemctl --now enable docker
官方自动安装脚本
curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun
sudo systemctl restart docker
docker run hello-world
常见安装错误
- problem with installed package podman
sudo dnf remove -y podman # 卸载podman
- problem with installed package buildah
yum install --allowerasing docker-ce
国内镜像加速
获取镜像加速地址
- 阿里云镜像服务 http://<你的ID>.mirror.aliyuncs.com
- 阿里云镜像服务申请 https://cr.console.aliyun.com/cn-hangzhou/instances/mirrors
- 网易镜像服务 http://hub-mirror.c.163.com
- 中科大镜像 https://docker.mirrors.ustc.edu.cn
配置镜像加速地址
mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["xxxxxxxxxxx"]
}
EOF
sudo systemctl daemon-reload && sudo systemctl restart docker
注: 请使用镜像地址替换上文xxxxxxxxxxx
镜像命令
获取镜像 pull
docker pull NAME[:TAG]
docker pull registry.hub.docker.com/NAME:TAG # 上面是这条命令的缩写
如果不指定TAG
,默认选择latest
标签。镜像文件由很多层组成。下载记录中,每行的开头代表了各层的ID
。层是AUFS(Advanced Union File System)
中的概念,是实现增量保存与更新的基础。
查看信息 images
docker images # 列出本机已有的镜像
# REPOSITORY TAG IMAGE ID CREATED SIZE
#来自于那个仓库 标签信息 镜像的ID号 创建时间 镜像大小
docker tag NAME[:TAG] NEWNAME[:NEWTAG] # 创建别名
docker inspect <IMAGE ID> # 镜像详细信息
docker inspect -f {{".Architecture"}} <IMAGE ID> # 删选部分信息
docker history [OPTIONS] IMAGE # 查看指定镜像的创建历史。
# --no-trunc : 显示完整的提交记录
# -H :以可读的格式打印镜像大小和日期
查找镜像 search
docker search [--automated=false] [--no-trunc=false] [-s, --starts=0] KEYWORD
# 仅显示自动创建的镜像 输出信息不截断显示 仅显示评价星级以上的
删除镜像 rmi
docker rmi [-f] IMAGE [IMAGE...]
当一个镜像有多个标签,rmi命令只是删除了指定的标签,不影响镜像文件。rmi命令删除镜像时,会先删除所有指向这个镜像的标签,然后才会删除镜像文件本身,注意这个命令必须是 docker rmi <IMAGE ID>
,而不是指定名字。当镜像被容器依赖时,不能被删除,除非加了 -f
,但是可能造成遗留问题。
创建镜像
基于已有镜像容器创建
docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]
# OPTIONS
# -a, --author="" 作者信息
# -m, --message="" 提交信息
# -p, --pause=true 提交时暂停容器运行
流程:
- 启动一个镜像
- 进行一些修改后退出
- 使用commit提交
docker run -ti centos:latest /bin/bash
touch testfile
exit
docker commit <之前的容器ID> # 这条命令会返回新的镜像ID
docker images
基于本地模板导入
-
从
openvz
下载一个模板 下载地址 -
使用命令
cat 下载的模板.tar.gz | docker import - <自定义名字>:<TAG>
基于Dockerfile创建
注意:Docker最多有127层Layer
Dockerfile有四部分
- 基础镜像信息
- 维护者信息
- 镜像操作指令
- 容器启动时执行指令
FROM ubuntu #指定基于什么的基础镜像,第一条指令必须是FROM指令
FROM <IMAGE>
FROM <IMAGE>:<TAG>
# FROM 可以有多个,用以在一个 Dockerfile文件中创建多个镜像
MAINTAINER m_docker_user docker_user@mail.com #维护者信息
MAINTAINER <NAME> # 指定维护者信息
# 镜像的操作指令
RUN echo "deb ..."
RUN apt-get update
RUN <COMMAND>
RUN ["EXECUTABLE","PARAM1","PARAM2"]
# 每运行一条run指令,镜像添加新的一层,并提交
CMD /bin/mysql #镜像启动时执行的指令,指定的是运行容器时的操作命令
CMD ["executable","param1","param2"]
CMD <COMMAND> <PARAM1> <PARAM1>
# CMD只能有一条,多条CMD只有最后一条会被执行
# 如果用户指定了运行时的命令,会覆盖掉 CMD 指定的指令
EXPOSE 22 80 443
EXPOSE <PORT> [<PORT>...]
# 指定的暴露的端口号,启动时需要用过 -P ,docker会自动分配一个端口转发到指定端口
# 使用 -p 可以具体指定那个本地端口映射过来
ENV PATH /usr/local/:$PATH
ENV <KEY> <VALUE> #指定一个环境变量,会被后续RUN使用,并在容器运行时保持
# 也可以通过在docker run ‐‐env key=value 时设置或修改环境变量
ADD <SRC> <DEST>
# 复制 <SRC> 到容器的 <DEST>。
# src可以是Dockerfile所在目录的一个相对路径,也可以是URL,也可以是tar文件(自动解压为目录)
COPY <SRC> <DEST>
# 和ADD命令一样,ADD支持 1.远程服务器通过URL获取资源 2.可以读取tar并自动解压
# COPY更建议用在本地
##---
# COPY指令和ADD指令的唯一区别在于是否支持从远程URL获取资源。
# COPY指令只能从执行docker build所在的主机上读取资源并复制到镜像中。
# ADD指令还支持通过URL从远程服务器读取资源并复制到镜像中。
# 大多数时间应该使用 COPY
##---
ENTRYPOINT ["executable","param1","param2"]
ENTRYPOINT command param1 param2 (shell执行)
# 配置容器启动后执行的命令,只有最后一个可以生效。
# ENTRYPOINT指令指定的命令不能被覆盖,而是将docker run指定的参数当做ENTRYPOINT指定命令的参数。
# CMD指令可以为ENTRYPOINT指令设置默认参数,而且可以被docker run指定的参数覆盖;
VOLUME ["/data"]
# 创建一个可以从本地主机或其他容器挂载的挂载点。
# 共享VOLUME :docker run ‐itd ‐volumes‐from container1 newimage /bin/bash
USER daemon
# 指定运行容器时的用户名或UID,后续的RUN也会使用指定用户
WORKDIR /path/workdir
# 为RUN,CMD,ENTRYPOINY指令配置工作目录
# 可以使用多个改命令,后续参数如果为相对路径,则会基于之前命令给予的路径
ONBUILD [INSTRUCTION]
#此镜像作为其他新创建镜像的基础镜像时执行的操作命令。
编写完Dockerfile之后,通过 docker build
创建镜像
使用 .dockerignore
文件让Docker忽略路径下的目录和文件
docker build [OPTIONS] PATH | URL | -
# --squash : 将 Dockerfile 中所有的操作压缩为一层。
# --tag, -t : 镜像的名字及标签,通常 name:tag 或者 name 格式
# -h : 打印帮助信息
存储和载入镜像 save load
存储镜像
docker save -o xxxx.tar <NAME>:<TAG>
载入镜像
docker load
不能对载入的镜像重命名
docker load --input xxxx.tar
docker load << xxxx.tar
上传镜像 push
# 给镜像打上 Tag
docker tag test:latest user/test:latest
# 推送镜像
docker push user/test:latest
容器命令
更新容器配置 update
docker update [OPTIONS] CONTAINER [CONTAINER...]
选项 | 描述 |
---|---|
--blkio-weight |
阻塞IO (相对权重),介于10到1000之间,0表示禁用(默认禁止) |
--cpu-period |
限制CPU CFS(完全公平的调度程序)期限 |
--cpu-quota |
限制CPU CFS(完全公平的调度程序)配额 |
--cpu-rt-period |
将CPU实时时间限制为微秒 |
--cpu-rt-runtime |
将CPU实时运行时间限制为微秒 |
--cpu-shares , -c |
CPU份额(相对权重) |
--cpus |
CPU数量 |
--cpuset-cpus |
允许执行的CPU(0-3,0,1) |
--cpuset-mem |
允许执行的MEM(0-3,0,1) |
--kernel-memory |
内核内存限制 |
--memory-swap |
交换限制等于内存加交换,“-1”以启用无限交换 |
--memory-reservatio |
内存软限制 |
--memory , -m |
内存限制 |
--pids-limit |
调节容器pids限制(-1表示无限制) |
--restart |
容器退出时重新启动策略以应用 |
列出容器 ps
docker ps
# -a, --all 显示所有的容器,默认只显示运行中的容器
# -f, --filter filter Filter output based on conditions provided
# --format string Pretty-print containers using a Go template
# -n, --last int Show n last created containers (includes all states) (default -1)
# -l, --latest 只列出最后创建的容器(包括所有状态)
# --no-trunc 不截断输出
# -q, --quiet 只输出容器ID
# -s, --size 显示文件使用大小
创建容器 create run
新创建的容器默认处于停止状态。
docker create -it <NAME>:<TAG> OR <IMAGE ID>
run命令可以新建一盒容器并启动,或重新启动一个终止状态的容器。
docker run -it <镜像名> /bin/bash
# -i: 使容器的标准输入保持打开。
# -t: 分配一个伪终端。并绑定到容器的标准输入上 /bin/bash:命令
# --name <NAME> 指定别名
# -d 守护态运行
# --rm 容器停止后立即删除,不能与 -d 同用
# -b BRIDGE OR --BRIDGE=BRIDGE 指定使用的网桥
# --restart=always Docker重启时,容器自动启动
# ‐‐network=网络名 将容器连接到网络
使用run
命令时,docker
的操作包括
-
检查本地是否有镜像,否则就下载。
-
利用镜像创建容器
-
分配一个文件系统,在只读镜像外挂在一层可读写层
-
从宿主机网桥接口桥接一个虚拟接口到容器
-
从地址池配置一个
IP
给容器 -
执行用户指定的应用程序
-
执行完毕后容器被终止
启动容器 start
docker start <容器 ID> #启动一个停止的容器,包含文件系统挂载的启动。
停止容器 stop
docker stop <容器 ID> [-t|--time[=10]] #包含文件系统卸载的停止
# 首先会发送SIGTERM信号,等待时间后发送SIGKILL终止容器。
docker kill CONTAINER
# 直接发送SIGKILL来终止容器
重启容器 restart
docker restart [-t|--time[=10]] <容器 ID>
# 重启一个正在运行的容器,不包含文件系统的操作
# 如果容器在运行,会将其终止后重新启动。
进入容器 attach exec
docker attach <容器 ID>
# 如果从这个容器退出,会导致容器停止
docker exec -it <容器 ID> /bin/bash
# exec是直接在容器里运行命令
# 如果从这个容器退出,容器不会停止
# -d, --detach 分离模式,在后台运行命令
# -u, --user 指定用户 格式: <name|uid>[:<group|gid>]
PID=$(docker inspect --format "{{.State.Pid}}" <container>)
nsenter --target $PID --mount --uts --ipc --net --pid
# 类似于docker exec,但是更底层
删除容器 rm
docker rm [-f , --force=false] [-l ,--link=false] [-v --volumes=false] <容器 ID>
# 强制终止并删除一个运行中的容器 删除容器的连接,但保留容器 删除容器挂载的数据卷
导入导出容器 export import
docker export <容器 ID> > file.tar #导出
cat file.tar | docker import - <镜像名>:[TAG] #导入成为镜像
# docker import 丢弃所有历史记录和元数据信息
# 仅保存容器当时的快照状态,比较小,且导入时可重新指定标签等
# docker load 保存完整记录,体积也比较大
DOCKER | |
---|---|
save | 保存的是镜像(image) |
export | 保存的是容器(container),导出的只是一个linux系统的文件目录 |
load | 载入镜像包,必须是一个分层文件系统,必须是是save的包;恢复为镜像 |
import | 载入容器包,恢复为镜像 |
网络管理 -P -p
docker create -it -P <NAME>:<TAG> OR <IMAGE ID>
docker create -it -p 5000:5000 <NAME>:<TAG> OR <IMAGE ID>
docker create -it -p 127.0.0.1:5000:80 <NAME>:<TAG> OR <IMAGE ID>
docker create -it -p 127.0.0.1::5000 <NAME>:<TAG> OR <IMAGE ID>
# 在创建的时候使用 `-P` 命令,将随机映射一个 49000-49900 的端口至容器内部开放的网络端口
# 在创建的时候使用 `-p 本地端口:容器端口 / IP:本地端口:容器端口 / ip::容器端口 ` 映射指定端口
# 映射所有接口地址 / 映射到指定地址的指定端口 / 映射到指定地址的任意端口
docker port <容器 ID> # 查看端口映射的配置
其他命令
system
docker system df [-v, --verbose] # 显示docker的磁盘占用
docker system events # 查看实时事件(例如容器创建,删除等)
docker system info # 查看docker 系统信息(同docker info)
docker system prune # 清理(清理停止的容器,没用容器使用的网络,镜像,缓存)
文件系统
联合文件系统(Union File System,Unionfs)是一种分层的轻量级文件系统,它可以把多个目录内容联合挂载到同一目录下,从而形成一个单一的文件系统,这种特性可以让使用者像是使用一个目录一样使用联合文件系统。默认情况下,只有第一层(第一个目录)是可写的,其余层是只读的。
OverlayFS 的发展分为两个阶段。2014 年,OverlayFS 第一个版本被合并到 Linux 内核 3.18 版本中,此时的 OverlayFS 在 Docker 中被称为overlay文件驱动。由于第一版的overlay文件系统存在很多弊端(例如运行一段时间后Docker 会报 "too many links problem" 的错误), Linux 内核在 4.0 版本对overlay做了很多必要的改进,此时的 OverlayFS 被称之为overlay2。
在目录/var/lib/docker/overlay2
下存存放着本机可写的层。
读取文件:
容器内进程读取文件分为以下三种情况。
- 文件在容器层中存在:当文件存在于容器层并且不存在于镜像层时,直接从容器层读取文件;
- 当文件在容器层中不存在:当容器中的进程需要读取某个文件时,如果容器层中不存在该文件,则从镜像层查找该文件,然后读取文件内容;
- 文件既存在于镜像层,又存在于容器层:当我们读取的文件既存在于镜像层,又存在于容器层时,将会从容器层读取该文件。
修改文件或目录:
overlay2 对文件的修改采用的是写时复制的工作机制,这种工作机制可以最大程度节省存储空间。 具体的文件操作机制如下。
- 第一次修改文件:当我们第一次在容器中修改某个文件时,overlay2 会触发写时复制操作,overlay2 首先从镜像层复制文件到容器层,然后在容器层执行对应的文件修改操作。因此,只要有对只读层中的文件做修改,不管修改数据的量的多少,在第一次修改时,文件都会被拷贝到可写层然后再被修改
- 删除文件或目录:当文件或目录被删除时,overlay2 并不会真正从镜像中删除它,因为镜像层是只读的,overlay2 会创建一个特殊的文件或目录, 使用 whiteout 机制,它的实现是通过在上层的可写的目录下建立对应的whiteout隐藏文件来实现的。这种特殊的文件或目录会阻止容器的访问。
文件查找
查找性能在层数非常多时会出现下降,层数越多,查找性能越低,因此,在制作 Docker 镜像时要注意层数不要太多。
增加文件
默认情况下,新增的文件都会被放在最上面的可写层中。
Docker 网络
基础概念
Docker
启动的时候会创建一个虚拟网桥docker0
,会根据RFC1918规定的私有网络地址分配获取一组地址。
典型的是172.17.42.1/16
,此后启动的容器内的网口也会分配统一网段 172.17.0.0/16
。容器和主机之间通过一对veth pair
接口进行通信。一端在docker0
上,以veth开头
。另一端则挂载在容器内。
Docker中默认的三种网络分别为bridge
、host
和none
,其中名为bridge
的网络就是默认的bridge
驱动网络,也是容器创建时默认的网络管理方式,配置后可以与宿主机通信从而实现与互联网通信功能,而host
和none
属于无网络,容器添加到这两个网络时不能与外界网络通信。
网络类型
- Bridge networks(桥接网络)
为了保证容器的安全性,我们可以使用基于bridge
的驱动创建新的bridge
网络,这种基于bridge
驱动的自定义网络可以较好的实现容器隔离。需要说明的是,这种用户自定义的基于bridge
驱动的网络对于单主机的小型网络环境管理是一个不错的选择,但是对于大型的网络环境管理(如集群)就需要考虑使用自定义overlay
集群网络。
- Overlay network in swarm mode(Swarm集群中的覆盖网络)
在Docker Swarm
集群环境下可以创建基于overlay
驱动的自定义网络。为了保证安全性,Swarm
集群使自定义的overlay网络只适用于需要服务的群集中的节点,而不会对外部其他服务或者Docker主机开放 。
- Custom network plugins(定制网络插件)
如果前面几种自定义网络都无法满足需求时,就可以使用Docker提供的插件来自定义网络驱动插件。自定义网络插件会在Docker进程所在主机上作为另一个运行的进程。自定义网络驱动插件与其他插件遵循相同的限制和安装规则,所有插件都使用Docker提供的插件API
,并且有一个包含安装、启动、停止和激活的生命周期。由于自定义网络插件使用较少,所以只需了解即可。
默认网络
docker
会自动创建三个网络 Host Bridge None 。
模式 | 说明 |
---|---|
Host | 容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口。在host 模式下,容器将不会获得一个独立的Network Namespace ,而是和宿主机共用一个Network Namespace 。使用--network=host 指定。 |
Bridge | 此模式会为每一个容器分配、设置IP等,并将容器连接到一个docker0 虚拟网桥,通过docker0 网桥以及Iptables nat 表配置与宿主机通信。除非特殊指定,每个docker 都会默认连接到此网络。使用--network=bridge 指定 |
None | 该模式关闭了容器的网络功能。使用 --network=none 指定。 |
Container | 创建的容器不会创建自己的网卡,配置自己的IP,而是和一个指定的容器共享IP、端口范围。在这个模式下,新创建的容器和已经存在的一个容器共享一个Network Namespace ,两个容器的进程可以通过lo网卡设备通信。使用--network=container:NAME_or_ID 指定。 |
DNS 和 主机名
-
/etc/resolv.conf - 在容器创建的时候,默认与宿主机保持一致
-
/etc/hostname - 记录了容器自身的一些地址和名称
-
/etc/hosts - 记录了容器的主机名
从 1.2.0
开始支持在容器里直接编辑以上文件,不过修改是临时的,只在运行的容器中保留,终止或重启后会重置,且不会被docker commit
提交。
-h HOSTNAME or --hostname=HOSTNAME 设定容器的主机名,但只有容器内能看到,外部和docker ps
以及其他docker /etc/hosts
都看不到。
--link=CONTAINER_NAME:ALIAS 使用这个选项创建容器,可以添加一个所连容器的主机名到容器内的/etc/hosts
中,这样新创建的容器可以直接使用主机名与连接的容器通信。
--dns=IP_ADDRESS 添加DNS
到容器的/etc/resolv.conf
--dns-search=DOMAIN 指定DNS搜索域。
访问控制
访问外部网络
在启动Docker
服务的时候设定 --ip-forward=true
,Docker
服务会自动打开宿主机系统的转发服务。
或打开转发开关
net.ipv4.ip_forward = 1
网络命令
列出网络
docker network ls
创建网络
docker network create [OPTIONS] <NAME>
# -d, --driver string 管理网络的驱动,默认是bridge
连接与断开网络
docker network connect <网络名> 容器
docker network disconnect <网络名> 容器
移除网络
docker network rm <网络名>
其他内容见高级用法