Docker组件:
- Docker客户端:Docker命令,例如  
docker pull centos:7 - Docker服务端:管理Docker服务,例如 
systemctl status docker - Image镜像:通过镜像才能运行容器
 - Container容器:容器是一个轻量级的虚拟机
 - Registry仓库:镜像存储在仓库中,可以存放在公共仓库,也可以搭建私有仓库
 
Docker底层:
- Cgroup:cgroup 实现资源限额,控制容器使用CPU、MEM、IO
 - Namespace:实现资源隔离,每个容器都是独立运行,拥有自己的网络、资源,互不影响
 
Group
全称 Control Group。Linux 操作系统通过 cgroup 可以设置进程使用 CPU、内存 和 IO 资源的限额
可以在 /sys/fs/cgroup 中找到它。还是用例子来说明,启动一个容器,设置 --cpu-shares=512
在 /sys/fs/cgroup/cpu/docker 目录中,Linux 会为每个容器创建一个 cgroup 目录,以容器长ID 命名
目录中包含所有与 cpu 相关的 cgroup 配置,文件 cpu.shares 保存的就是 --cpu-shares 的配置,值为 512。
同样的,/sys/fs/cgroup/memory/docker 和 /sys/fs/cgroup/blkio/docker 中保存的是内存以及 Block IO 的 cgroup 配置。
Namespace
在每个容器中,我们都可以看到文件系统,网卡等资源,每个容器都会认为自己有一块独立的网卡,即使 host 上只有一块物理网卡。
这种方式非常好,它使得容器更像一个独立的计算机。Linux 实现这种方式的技术是 namespace。
namespace 管理着 host 中全局唯一的资源,并可以让每个容器都觉得只有自己在使用它。换句话说,namespace 实现了容器间资源的隔离。
Linux 使用了六种 Namespace,分别对应六种资源:Mount、UTS、IPC、PID、Network 和 User
Mount:文件系统 容器有自己的 / 目录,可以执行 mount 和 umount 命令。当然我们知道这些操作只在当前容器中生效,不会影响到 host 和其他容器。UTS:让容器有自己的 hostname。 默认情况下,容器的 hostname 是它的短ID,可以通过 -h 或 —hostname 参数设置。IPC:让容器拥有自己的共享内存和信号量(semaphore)来实现进程间通信,而不会与 host 和其他容器的 IPC 混在一起。PID:所有容器的进程都挂在 dockerd 进程下,同时也可以看到容器自己的子进程。 如果我们进入到某个容器,ps 就只能看到自己的进程了Network:让容器拥有自己独立的网卡、IP、路由等资源。我们会在后面网络章节详细讨论。User:让容器能够管理自己的用户,host 不能看到容器中创建的用户
镜像
下载镜像
docker pull ubuntudocker pull ubuntu:18.04
列出镜像
docker images列出镜像docker image ls -f dangling=true查看虚悬镜像- 虚悬镜像 镜像和标签都为none,悬空镜像没有意义,浪费磁盘空间可以删除
 
docker image prune清空无用的悬空镜像docker images -a查看中间层镜像- 中间层镜像名称和标签都是none,有被别的镜像依赖是不能被删除
 
docker system df查看镜像、容器、数据卷所占用的空间docker images ls ubuntu查看镜像docker images ls ubuntu:18.04查看镜像docker image ls -f since=mongo:3.2-f过滤器参数 镜像有创建时间,since表示查看在这镜像之后的镜像docker image ls -f before=mongo:3.2镜像建立之后的镜像docker image ls -f label=com.example.version=0.1只查看含有该标签的镜像docker image ls -q只显示镜像IDdocker image ls --digests显示长的镜像信息- 显示镜像信息
 
# 只显示镜像ID和仓库名docker image ls --format "{{.ID}}: {{.Repository}}"# 显示镜像ID和仓库名、标签docker image ls --format "{{.ID}}\t{{.Repository}}\t{{.Tag}}"# 多显示一行开头docker image ls --format "table {{.ID}}\t{{.Repository}}\t{{.Tag}}"
删除镜像
docker rmidocker rmi $(docker images | grep "^<none>" | awk "{print $3}")
上传镜像
# 登录docker.hub,输入你的账号和密码,出现login susses提示表示登录成功docker login# 退出登录docker logout# 查找镜像docker search centos#下载镜像docker pull centos# 用户名haoxinchengdocker tag ubuntu:18.04 haoxincheng/ubuntu:18.04# 提交镜像docker push haoxincheng/ubuntu:18.04# 查找镜像docker search haoxincheng
私有仓库
官方registry、Harbor vmware公司的私有仓库
使用官方registry,
docker run -d \-p 15000:5000 \-v /opt/data/registry:/var/lib/registry \registry
容器
基础使用
docker run ubuntu:18.04 /bin/echo 'Hello world'容器运行命令docker run -it ubuntu:18.04 /bin/bash-t分配为tty伪终端,-i容器的标准输入保持打开,-it2个结合使用docker run -it --rm ubuntu:18.04 bash—rm容器退出后,删除该容器,避免浪费磁盘资源docker run -dit ubuntu后台运行容器docker run ubuntu:18.04 /bin/sh -c "while true; do echo hello world; sleep 1; done"前台运行,日志打印在终端上docker run -d ubuntu:18.04 /bin/sh -c "while true; do echo hello world; sleep 1; done"后台运行,通过docker logs查看日志docker run -dit --restart=always ubuntu无论容器因何种原因退出(包括正常退出),就立即重启docker run -dit --restart=on-failure:3 ubuntu启动进程退出代码非0,则重启容器,最多重启3次docker start启动容器docker stop停止容器docker restart重启容器
删除容器
docker image rm centos删除镜像docker image rm 501删除镜像,可以用短ID,最前面3个就可以docker image rm 501 centos删除多个镜像docker image rm $(docker image ls -q redis)调用命令docker image rm $(docker image ls -q -f before=mongo:3.2)删除该镜像之后的容器
端口映射
docker run --name webserver -d -P nginx—name自定义容器名,大P随机指定映射到宿主机的端口docker run --name webserver -d -p 80:80 nginx宿主机:容器端口docker run -d -p 127.0.0.1:80:80 nginx:alpine指定IP、宿主机端口、容器端口docker run -d -p 127.0.0.1::80 nginx:alpine指定IP、容器端口docker run -d -p 127.0.0.1:80:80/udp nginx:alpine指定协议为udpdocker run -d -p 80:80 -p 443:443 nginx:alpine映射多个端口docker port web查看容器端口映射 ,docker port web 443 查看容器端口映射指定端口
资源限制
MEM 限制
docker run -m 200M ubuntu分配200M内存docker run -m 200M --memory-swap=300M ubuntu允许该容器最多使用 200M 的内存和 100M 的 swap。默认情况下,没有限制docker run -it -m 200M --memory-swap=300M progrium/stress --vm 1 --vm-bytes 280M启动 1 个内存工作线程,每个线程分配 280M 内存,vm-bytes是压力测试docker run -it -m 200M --memory-swap=300M progrium/stress --vm 1 --vm-bytes 310M压力测试超过310M就会报错,分配的内存超过限额,stress 线程报错,容器退出docker run -it -m 200M ubuntu在启动容器时只指定 -m 而不指定 —memory-swap,那么 —memory-swap 默认为 -m 的两倍。容器最多使用 200M 物理内存和 200M swap
CPU 限制
docker run --name "container_A" -c 1024 ubuntu progrium/stress --cpu 1- -c 配置优先级,越大越优先,容器A使用的CPU资源是比容器B更加优先的
 - —cpu是使用cpu的核数,当宿主机有多核cpu可以用该参数限制使用
 - 通过宿主机top命令查看占用,如果将容器A停止,那么CPU资源都是给容器B使用
 
docker run --name "container_B" -c 512 ubuntu progrium/stress --cpu 1
IO 限制
docker run -it --device-write-bps /dev/sda:30MB ubuntu- 默认磁盘不限制iops,此时进入容器time dd if=/dev/zero of=test.dbf bs=8k count=300000,会看到速度被限制了
 - —device-read-bps,限制读某个设备的 bps。
 - —device-write-bps,限制写某个设备的 bps。
 - —device-read-iops,限制读某个设备的 iops。
 - —device-write-iops,限制写某个设备的 iops。
 
docker run -it --name container_A --blkio-weight 600 ubuntu—blkio-weight 与 —cpu-shares 类似,设置的是相对权重值,默认500,container_A 读写磁盘的带宽是 container_B 的两倍docker run -it --name container_B --blkio-weight 300 ubuntu
容器网络
None网络 就是什么都没有的网络。挂在这个网络下的容器除了 lo,没有其他任何网卡。封闭网络存放安全的数据
--network 等同于 --net
docker run -it --network=none busybox
Host共享 Docker host 的网络栈,容器的网络配置与 host 完全一样,进入容器使用IP命令查看
docker run -it --network=host busybox
Bridge网络 自定义网络,默认创建容器是使用docker的Bridge
docker network create -d bridge my_net# 宿主机操作,查看Bridge的网络结构yum -y install bridge-utils && brctl show# 创建时指定网段docker network inspect -d bridge --subnet 172.22.16.0/24 --gateway 172.22.16.1 my_test## 查看网络docker network inspect my_testdocker run -it --network=my_test busyboxdocker run -it --network=my_test --ip 172.22.16.88 busyboxdocker run -it --network=my_test --ip 172.22.16.89 busybox
DNS信息
mount #可以看到docker容器的挂载信息
进入容器,进行ping,你会发现2个容器是可以通信的
/etc/docker/daemon.json
{"dns" : ["114.114.114.114","8.8.8.8"]}
$ docker run -it --rm ubuntu:18.04 cat etc/resolv.confnameserver 114.114.114.114nameserver 8.8.8.8
数据挂载
将宿主机的目录、文件挂载到容器的目录、文件
注意事项:
- 容器目录可以是空目录,最好提前创建该目录,挂载参数为相对路径
 - 某些容器可能不支持,例如busybox挂载后始终无法同步主机的数据 
docker run -it -v /opt/docker/busybox:/home busybox - 多个容器也可以挂载同一个宿主机目录,但是不建议该操作,可能造成数据混乱
 - 不能挂载容器的范围很大,比分说镜像inspect规定了范围,指定超出的路径范围就会出问题
 - 挂载文件的坏处: 挂载文件不挂载目录,可能造成文件修改不同步的问题,通过vim的方式编辑并不会同步问题,因为备份原来的文件,当新文件编辑完成后,再将新文件替换文原件,这会导致文件的inode变化,所以docker内外的文件并不会同步,
而用echo等重定向操作修改文件时,文件的inode保持不变,所以不会发生类似现象 
常用挂载命令:
docker run -d -P --name web -v /webapp training/webapp python app.pydocker run -d -P --name web -v /src/webapp:/opt/webapp:ro training/webapp python app.py挂载目录,只读权限docker run --rm -it -v ~/.bash_history:/.bash_history ubuntu /bin/bash-v标识还可以将宿主机的一个特定文件挂载为数据卷
常见问题
docker run -d \--name gitlab \-p 80:80 \-p 8443:443 \-v /opt/docker/gitlab/etc:/etc/gitlab \-v /opt/docker/gitlab/var/log:/var/log/gitlab \-v /opt/docker/gitlab/var/opt:/var/opt/gitlab \twang2218/gitlab-ce-zh:latest
很多镜像用-v选项挂载会有问题,因为你挂载的范围有点大了,此时会报错出/var/lib路径有问题
docker run -d \--name gitlab \-p 80:80 \-p 8443:443 \-v /opt/docker/gitlab/var:/var \-v /opt/docker/gitlab/etc:/etc/gitlab \twang2218/gitlab-ce-zh:latest
如果还是想这么挂载大范围,那么解决方法是先跑一遍容器,然后把容器数据复制到宿主机,然后再挂载
docker run -d \--name gitlab \-p 80:80 \-p 8443:443 \-v /opt/docker/gitlab/var:/var \-v /opt/docker/gitlab/etc:/etc/gitlab \twang2218/gitlab-ce-zh:latest
如果不确定镜像挂载是什么样的,可以通过docker inspect命令查看镜像信息
docker diff webserver查看容器文件的更改变化docker logs -f 9123查看容器日志docker attach 243c如果exit退出,那么容器也会停止(了解即可,不要使用)docker exec -it 69d1 bash如果exit推出,容器依然运行,所以不要用attachdocker pause my有时我们只是希望暂时让容器暂停工作一段时间,比如要对容器的文件系统打个快照,或者 dcoker host 需要使用 CPU。处于暂停状态的容器不会占用 CPU 资源,直到通过 docker unpause 恢复运行。docker unpause my恢复容器运行
删除容器
docker rm -f-f参数强制停止正在运行的容器docker rm -v $(docker ps -aq -f status=exited)批量删除已经停止的容器docker container prune清理无用的、已经停止的容器
打包镜像
Dockerfile
docker commit
当容器做出了更改,可以通过 docker commit 对已有容器打包为镜像
缺点:
- commit会让构建臃肿
 - 不清楚对容器之前的操作过程,时间长了无法管理
 
docker commit \--author "Tao Wang <twang2218@gmail.com>" \--message "修改了默认网页" \webserver \nginx:v2 #author作者信息、message记录修改的内容,这2个可以不用加,加上更加清楚docker image ls nginx #docker history nginx:v2 #查看镜像的历史记录,可以知道容器第一次启动的命令是什么docker run --name web2 -d -p 81:80 nginx:v2
docker export
# 容器制作成镜像docker export 7691a814370e > ubuntu.tar# 导入本地镜像cat ubuntu.tar | docker import - test/ubuntu:v1.0# 也可以通过网络资源导入为镜像docker import http://example.com/exampleimage.tgz example/imagerepo# 查看镜像docker images
docker load
常见问题 Error response from daemon: No command specified
镜像没有容器第一次命令,所以创建容器时需要指定命令,后来发现是导入的方式不对
原来镜像是通过docker save方式保存的,所以必须要用docker load方式导入,不然会有问题
[root@jq-test ~]# docker inspect jq/gitlab|grep -i cmd"Cmd": null,"Cmd": null,
容器访问外网
容器访问控制,宿主机打开Linux内核路由转发,通过iptables控制容器的通信
sysctl net.ipv4.ip_forward #查看sysctl -w net.ipv4.ip_forward=1 #为1开启转发,为0不转发
iptables -nL
iptables -nL
iptables -t nat -nL #查看Chain DOCKER表的规则
如果希望永久绑定到某个固定的 IP 地址,可以在 Docker 配置文件  中添加如下内容。
{"ip": "0.0.0.0"}
Docker 1.2.0 开始支持在运行中的容器里编辑 /etc/hosts, /etc/hostname 和 /etc/resolv.conf 文件。
但是这些修改是临时的,只在运行的容器中保留,容器终止或重启后并不会被保存下来,也不会被 docker commit 提交。
容器数据
docker volume create my-vol #创建数据卷docker volume ls #查看所有的数据卷docker volume inspect my-vol #查看指定数据卷的信息docker run -d -P \--name web \# -v my-vol:/usr/share/nginx/html \--mount source=my-vol,target=/usr/share/nginx/html \nginx:alpine不能含有注释,不然无法运行docker run -d -P \--name web \--mount source=my-vol,target=/usr/share/nginx/html \nginx:alpinedocker volume rm my-vol #删除数据卷docker rm -v # 删除容器是不会删除数据卷的,-v可以删除数据卷docker run -d -P \--name web \-v /src/webapp:/usr/share/nginx/html \nginx:alpinedocker run -d -P \--name web \--mount type=bind,source=/src/webapp,target=/usr/share/nginx/html \nginx:alpine # 挂载一个主机目录作为数据卷。以前使用 -v 参数时如果本地目录不存在 Docker 会自动为你创建一个文件夹,现在使用 --mount 参数时如果本地目录不存在,Docker 会报错。docker run -d -P \--name web \--mount type=bind,source=/src/webapp,target=/usr/share/nginx/html,readonly \nginx:alpine #只读挂载,容器是无法进行写操作的docker inspect web 挂载主机目录 的配置信息在 "Mounts" Key 下面
docker top sysdig 查看容器运行的进程使用的资源
docker stats 0所有容器各个资源的使用情况
docker stats sysdig 容器
docker run -d -p 9100:9100 
-v “/proc:/host/proc” 
-v “/sys:/host/sys” 
-v “/:/rootfs” 
—net=host 
prom/node-exporter 
—path.procfs /host/proc 
—path.sysfs /host/sys 
—collector.filesystem.ignored-mount-points “^/(sys|proc|dev|host|etc)($|/)”
配置Docker远程访问
"hosts": ["tcp://0.0.0.0:2375","unix://var/run/docker.sock"]
example: docker -H Ip:Port Comman
