Docker介绍
- 支持Linux、Windows、Mac等系统
- 传统虚拟化(虚拟机)是在硬件层面实现虚拟化,需要额外的虚拟机管理应用和虚拟机操作系统层。Docker容器是在操作系统层面实现虚拟化,直接复用本地本机的操作系统,因此更加轻量级。
- Docker镜像存在版本和仓库的概念,类似Git。docker官方仓库为Docker Hub
- 官方文档
- 在线docker测试地址
- docker基础镜像包含
alpine
(apk)、centos
(yum)、ubuntu
(apt-get)三种 - 本文基于docker版本
Server Version: 1.13.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## 设置镜像,docker-compose拉取镜像时可生效
vi /etc/docker/daemon.json # 加入下文配置
{"registry-mirrors": ["https://docker.mirrors.ustc.edu.cn"]}
# 重启
sudo systemctl daemon-reload
sudo systemctl restart docker
## docker.io镜像加速。参考:https://juejin.im/post/5cd2cf01f265da0374189441
# 中科大 `docker.mirrors.ustc.edu.cn`;网易 `hub-mirror.c.163.com`;阿里云私有加速器(只有部分镜像) `bzyep49h.mirror.aliyuncs.com`
docker pull xxx:yyy "可替换为" docker pull docker.mirrors.ustc.edu.cn/library/xxx:yyy
docker pull xxx/yyy:zz "可替换为" docker pull docker.mirrors.ustc.edu.cn/xxx/yyy:zz
# Azure中国镜像 `dockerhub.azk8s.cn`
## gcr.io镜像加速
# 中科大 `gcr.mirrors.ustc.edu.cn`
docker pull gcr.io/xxx/yyy:zzz "可替换为" docker pull gcr.mirrors.ustc.edu.cn/xxx/yyy:zzz
# Azure中国镜像 `gcr.azk8s.cn`
## k8s.gcr.io镜像加速。k8s.gcr.io等价于gcr.io/google-containers
# 中科大 `gcr.mirrors.ustc.edu.cn/google-containers`
docker pull k8s.gcr.io/xxx:yyy "可替换为" docker pull gcr.mirrors.ustc.edu.cn/google-containers/xxx:yyy
# Azure中国镜像 `gcr.azk8s.cn/google-containers`
# 阿里云 `registry.aliyuncs.com/google_containers`
## quay.io镜像加速
# 中科大 `quay.mirrors.ustc.edu.cn`
# Azure中国镜像 `quay.azk8s.cn`
# 七牛镜像 `quay-mirror.qiniu.com`
docker pull quay.io/xxx/yyy:zzz "可替换为" docker pull quay.mirrors.ustc.edu.cn/xxx/yyy:zzz
安装
- Windows
- Windows 10直接使用windows安装包 https://hub.docker.com/editions/community/docker-ce-desktop-windows
- 执行docker命令时提示
docker for windows could not read CA certificate
,解决https://blog.csdn.net/qq_35852248/article/details/80925154 - 使用的网卡为
Hyper-V
,会导致VMware和DockerToolbox无法运行。可在控制面板 - 程序和功能 - 关闭windows的Hyper-V功能
- 执行docker命令时提示
- 通过安装
DockerToolbox
,安装文档和下载地址- 安装完成后桌面快捷方式:
Docker Quickstart Terminal
、kitematic
、Oracle VM VirtualBox
Docker Quickstart Terminal
可快速启动docker虚拟机,并进入到bash命令行kitematic
是docker推出的GUI界面工具(启动后,会后台运行docker,即自动运行docker虚拟机)Oracle VM VirtualBox
其实是一个虚拟机管理程序,docker就运行在此default虚拟机上- 下载的docker镜像在虚拟硬盘上,default虚拟机内存默认是1G,很容易内存溢出导致容器无法运行,可以在VirtualBox中进行调整
- 虚拟机启动默认用户为
docker/tcuser
,可通过ssh docker@192.168.99.100
进入此虚拟机
- 运行
Docker Quickstart Terminal
,提示找不到bash.exe
,可以浏览选择git中包含的bash(或者右键修改此快捷方式启动参数。目标:"D:\software\Git\bin\bash.exe" --login -i "D:\software\Docker Toolbox\start.sh"
)。第一次启动较慢,启动成功会显示docker的图标 - 如果DockerToolbox运行出错
Looks like something went wrong in step ´Checking status on default..
,可以单独更新安装VirtualBox
- xshell连接docker虚拟机:http://blog.aezo.cn/2017/06/24/extend/vmware/
- 安装完成后桌面快捷方式:
- 或者安装Boot2Docker
- 如果设置了C盘搬家到D盘,容易出现磁盘占满问题。可将虚拟机的disk.vmdk直接移动到D盘,步骤如下
- 复制
C:\Users\smalle\.docker\machine\machines\default\disk.vmdk
到D:/data/docker/disk.vmdk
- 进入VirtualBox(4.0.4以上)安装目录,执行
VBoxManage internalcommands sethduuid D:/data/docker/vdisk.vmdk
重设磁盘UUID - 打开VirtualBox,删除default原有的磁盘,然后添加新磁盘指向D:/data/docker/disk.vmdk
- 复制
- windows命令行运行docker命令提示无此命令,可将
D:\software\Docker Toolbox
加入到Path中
- Windows 10直接使用windows安装包 https://hub.docker.com/editions/community/docker-ce-desktop-windows
linux
1
2
3
4
5
6
7yum install docker # 安装
# 数据文件默认保存在`/var/lib/docker`下,建议先进行修改,修改后此目录可不用保存
vi /etc/docker/daemon.json
{"registry-mirrors": ["https://docker.mirrors.ustc.edu.cn"], "graph": "/data/docker", "dns" : ["114.114.114.114", "8.8.8.8"]}
# 重启
sudo systemctl daemon-reload && sudo systemctl restart dockerubuntu安装
1
2
3sudo apt-get install docker.io
sudo gpasswd -a ${USER} docker # 把当前用户加入到docker组
cat /etc/group | grep ^docker # 查看是否添加成功启动
systemctl start docker
命令
docker
1 | docker # docker 命令帮助 |
镜像
- 获取镜像
docker pull NAME[:TAG]
拉取镜像。如:docker pull nginx:latest
(同:docker pull nginx
,省略TAG则默认为latest
)docker pull www.aezo.cn/aezocn/smtools:latest
从私有镜像站下载镜像(www.aezo.cn/aezocn/smtools为repository,latest为tag)
docker images
列出所有本地镜像docker inspect c28687f7c6c8
获取某个image ID的详细信息
docker search mysql
搜索远程仓库镜像- 查看某个Name的所有TAG:如centos访问
https://hub.docker.com/r/library/centos/tags/
查看
- 查看某个Name的所有TAG:如centos访问
- 运行镜像
docker run -it busybox
运行busybox镜像,并进入容器(本地无此镜像时,会自动pull)。BusyBox 是一个集成了三百多个最常用Linux命令和工具的软件docker run -dt -p 8080:80 nginx
后台运行nginx镜像(包含创建一个容器)
- 提交镜像
docker commit -m 'commit message' -a 'author info' c28687f7c6c8 my_repositor_name
基于某容器ID创建镜像(对该容器进行了改动后的提交)docker tag 7042885a156a 192.168.17.196:5000/nginx
给某镜像打一个标签,此时不会生成一个新镜像(镜像ID还是原来的). 192.168.17.196:5000/nginx 很重要,之后可以推送到私有仓库192.168.17.196:5000(ip地址一定要一样),推送上去的镜像为nginx:latest
- 构建镜像
docker build --rm -f /path/to/a/Dockerfile .
从Dockerfile构建镜像
- 删除镜像
docker image rm c28687f7c6c8
删除镜像(-f 强制删除)docker rmi $(docker images -f "dangling=true" -q)
清除坏的<none>:<none>
镜像docker images -a|grep none|awk '{print $3 }'|xargs docker rmi
容器
docker run -it image_id_c28687f7c6c8 /bin/echo 'hello world'
创建并启动容器(如果没有则会从远程仓库下载)docker create -it c28687f7c6c8
基于镜像创建容器,但不启动docker start a8f590736b62
启动容器 (不会进入容器,启动后回到shell)docker stop a8f590736b62
停止容器docker update --restart=always a8f590736b62
更新运行中的容器配置(包括还可以更新CPU/MEM分配等,此处更新其重启类型restart为always)- 启动后的容器需要添加新端口可以走端口映射,或者先提交成镜像然后再运行一个容器
docker ps
列出运行的容器docker ps -a
列举所有容器
docker exec -it <container_id | container_name> bash
运行容器中的命令,此时会进入容器shell;此时容器必须处于启动状态;exit
可退出容器命令行(并不会关闭容器)docker exec -dt <container_id | container_name> ls
运行容器中的命令,但是不会进入容器docker exec -it <container_id | container_name> /bin/bash -c 'ls'
也不会进入容器
docker attach <container_id | container_name>
进入某运行的容器 (组合建ctrl+p+q退出),部分容器无法使用ctrl+p+q退出docker inspect a8f590736b62
查看容器详细(存储、网络等)。详细--format
语法如下(Go模板语法) ^81
2
3
4
5
6
7
8
9
10
11
12
13
14
15## 查看nginx绑定的端口
# {{println}}为打印换行
# range相当于循环,需要和{{end}}配合
# $k,$v为自定义变量,用来接收.NetworkSettings.Ports的map
# (index $v 0)表示基于索引获取$v的属性为0的数值,如果是数组则是取$v[0]的值;也可用于map取键含特殊字符的值,如:(index $map "my.key.com.test")
sudo docker inspect --format '{{/*注释:通过变量组合展示容器绑定端口列表*/}}已绑定端口列表:{{println}}{{range $k,$v := .NetworkSettings.Ports}}{{$k}} -> {{(index $v 0).HostPort}}{{println}}{{end}}' nginx
# 已绑定端口列表:
# 443/tcp -> 443
# 4443/tcp -> 4443
# 80/tcp -> 2080
## 查看所有容器使用的网卡信息
sudo docker inspect --format='{{.Name}} => {{range $k,$v := .NetworkSettings.Networks}}{{$k}}->{{.IPAddress}}{{end}}' $(sudo docker ps -aq)
# /nginx => harbor_harbor->172.18.0.8
# /jenkins => bridge->172.17.0.2docker rm a8f590736b62
删除容器ID为a8f590736b62的容器docker rename 原容器名 新容器名
重命名容器名(运行也可重命名)
docker网络
网络类型:host、bridge(默认)、container、none. 使用如:
docker run --network=host busybox
host
和宿主主机使用相同的网络(包括端口,此时无需-p指定端口映射)bridge
桥接模式。中间通过docker0
虚拟网卡(docker默认网卡)进行网络传输。此时与外网连通,需要开启ip转发- 从docker0子网中分配一个IP给容器使用,并设置docker0的IP地址为容器的默认网关。在主机上创建一对虚拟网卡veth pair设备,Docker将veth pair设备的一端放在新创建的容器中,并命名为eth0(容器的网卡),另一端放在主机中,以vethx这样类似的名字命名,并将这个网络设备加入到docker0网桥中。可以通过
brctl show
命令查看 需开启宿主机IP转发,此时宿主主机相当于一个NAT,容器的
eth0
通过docker规定的网络接口与docker0
连接,docker0
又处于宿主主机当容器向公网发起请求时 -> 容器的
eth0
->docker0
-> (由于开启ip转发)宿主主机eth0
-> 此时原地址会改成宿主主机向公网发送IP包1
2
3
4
5
6
7
8## 临时开启转发(1是允许转发,0不允许转发)
echo 1 > /proc/sys/net/ipv4/ip_forward
## 永久修改,加入配置
# net.ipv4.ip_forward=1
# net.ipv6.conf.all.forwarding=1
sudo vi /etc/sysctl.conf
# 使文件生效
sudo sysctl -p /etc/sysctl.conf
- 从docker0子网中分配一个IP给容器使用,并设置docker0的IP地址为容器的默认网关。在主机上创建一对虚拟网卡veth pair设备,Docker将veth pair设备的一端放在新创建的容器中,并命名为eth0(容器的网卡),另一端放在主机中,以vethx这样类似的名字命名,并将这个网络设备加入到docker0网桥中。可以通过
container
容器和另外一个容器共享Network namespace。 kubernetes中的pod就是多个容器共享一个Network namespace--network=container:web1
指定 jointed 容器为 web1
none
Docker容器拥有自己的Network Namespace,但是,并不为Docker容器进行任何网络配置。也就是说,这个Docker容器没有网卡、IP、路由等信息。需要我们自己为Docker容器添加网卡、配置IP等。这种网络模式下容器只有lo回环网络,没有其他网卡
- docker部署在本地虚拟机上
- 此时docker的宿主主机为虚拟机,虚拟机和本地机器属于同一网络。然后在docker中启动一个容器,docker会自动在宿主主机上创建一个虚拟网络,用于桥接宿主主机和容器内部网络
- 容器会继承docker宿主主机的网络,在容器内部是可以向外访问到宿主主机所在网络,如本地物理机
- 在本地物理机中默认是无法访问容器内网络,当开启端口映射8080:80时,可通过访问宿主主机的映射端口(8080)达到访问容器的内部端口(80)
- docker部署在内网的其他机器上,同上理。需要注意容器内部访问宿主主机内网其他机器时,需要该机器没有开启VPN,虚拟网卡(会产生多个ip)等
- Docker操纵
iptables
规则以提供网络隔离(会定时重置iptables规则)。如果需要添加在Docker规则之前加载的规则,需将添加到DOCKER-USER
(filter表)链中。也可通过参数关闭docker对iptables的操作
docker跨容器通信
- host、bridge、container、none解决了单个 Docker Host 内容器通信的问题
- 跨(宿主机)容器通信解决方案
- 可通过直接路由方式(NAT)
- 桥接方式(如pipework)完成跨容器通信(二层VLAN网络,大二层方式,只适合小于4096节点集群,且存在广播风暴问题)
- docker 内置的 Overlay 和 macvlan 则解决了跨容器通信,第三方方案常用的包括 flannel、weave、calico
Overlay网络
- Overlay网络是指在不改变现有网络基础设施的前提下,通过某种约定通信协议,把二层报文封装在IP报文之上的新的数据格式。这样不但能够充分利用成熟的IP路由协议进程数据分发,而且能够突破VLAN的4096数量限制,支持高达16M的用户,并在必要时可将广播流量转化为组播流量,避免广播数据泛滥
三种Overlay的实现标准,分别是:虚拟可扩展LAN(VxLAN)、采用通用路由封装的网络虚拟化(NVGRE)和无状态传输协议(SST),其中以VxLAN的支持厂商最为雄厚,VxLan数据包格式
- 为支持容器跨主机通信,Docker 提供了 overlay driver。Docerk overlay 网络需要一个 key-value 数据库用于保存网络状态信息,包括 Network、Endpoint、IP 等。Consul、Etcd 和 ZooKeeper 都是 Docker 支持的 key-vlaue 软件
- Overlay方案实践(Host0: 192.168.6.10, Host1: 192.168.6.131, Host2: 192.168.6.132) ^11
1 | ## 准备 overlay 环境(Linux 3.10.0-957.el7.x86_64 可成功部署) |
原理说明
network namespace
- docker 会为每个 overlay 网络创建一个独立的 network namespace(1-da3d1b5fcb),其中包含一个 linux bridge br0设备。 veth pair 一端连接到容器中(即 容器eth0),另一端连接到 namespace 的 br0 上(vethx)
- br0 除了连接所有的 veth pair,还会连接一个 vxlan 设备,用于与其他 host 建立 vxlan tunnel,容器之间的数据就是通过这个 tunnel 通信的。vxlan是个特殊设备,收到包后,由vxlan设备创建时注册的设备处理程序对包进行处理,即进行VXLAN封包(这期间会查询consul中存储的net1信息),将ICMP包整体作为UDP包的payload封装起来,并将UDP包通过宿主机的eth0发送出去
查看 overlay 网络的 namespace(测试为1-e5c4953846)
1
2
3
4
5
6
7
8
9
10
11# 查看 overlay 网络的 namespace
ln -s /var/run/docker/netns /var/run/netns
# 如显示的`1-e5c4953846`标识会在 `docker network ls` 找到类似的NETWORK ID(开头一致,可能最后几个字母没有显示)
ip netns
# 查看此命名空间网络接口,包含有:lo、br0、vxlan1、veth2@if455(veth2)
# vxlan1 为 overlay network的一个 VTEP,即VXLAN Tunnel End Point – VXLAN隧道端点。VXLAN的相关处理都在VTEP上进行,例如识别以太网数据帧所属的VXLAN、基于 VXLAN对数据帧进行二层转发、封装/解封装报文等
# 同一个overlay网络中,每个docker对应一个vethx(`docker exec -it centos1 ethtool -S eth0` 显示的网卡序号和此时查询到的vethx的序号会相互对应)
# ip netns exec 1-e5c4953846 xxx 相当于基于此 network namespace 运行相关网络命令。也可进行抓包:ip netns exec 1-e5c4953846 tcpdump -i veth2 -n icmp
ip netns exec 1-e5c4953846 ip a
# 查看此命名空间网桥接口
ip netns exec 1-e5c4953846 brctl show
数据流向
- 同一个Overlay网络(net1)不同宿主机(蓝色为宿主机,白色虚框为容器)
- 数据包从容器eth0发出
- 经过vxlan1时进行VxLAN封包处理(这期间会查询consul中存储的overlay信息),将ICMP包(ping)整体作为UDP包的payload封装起来,并将UDP包通过宿主机的eth0发送出去
- 宿主机收到UDP包后,发现是VXLAN包,根据VXLAN包中的相关信息(比如Vxlan Network Identifier,VNI=256)找到vxlan设备,并转给该vxlan设备处理
- vxlan设备的处理程序进行解包,并将UDP中的payload取出,整体通过br0转给vethx接口
- 不同Overlay网络相同宿主机
- 数据包从容器eth1发出,经过docker_gwbrige进行传输。普通网络默认是桥接在docker0网卡上,而所有Overlay网络则桥接在docker_gwbrige网卡上进行通讯
- 同一个Overlay网络(net1)不同宿主机(蓝色为宿主机,白色虚框为容器)
手动安装Consul
- Consul是一个分布式高可用的系统,可用于服务发现、Key/Value存储等
1 | wget https://releases.hashicorp.com/consul/1.5.2/consul_1.5.2_linux_amd64.zip |
Dockerfile
- 在大部分情况下,Dockerfile 会和构建所需的文件放在同一个目录中,为了提高构建的性能,应该使用
.dockerignore
来过滤掉不需要的文件和目录 docker build --rm -t my-nginx:latest -f /home/smalle/Dockerfile .
从Dockerfile构建镜像 ^41
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# This my first nginx Dockerfile
# Version 1.0
# FROM 基础镜像
FROM bzyep49h.mirror.aliyuncs.com/library/centos
# MAINTAINER 维护者信息
MAINTAINER smalle
# ARG获取外部环境变量,也可以定义默认值,ARG可以在Dockerfile文件第一行接受外部参数
# docker build --build-arg SQ_DOCKER_REGISTRY=192.168.6.131:5000 --build-arg APP_VERSION=v1.1.1 .
ARG APP_VERSION=v1.0.0
# ENV 设置环境变量。可读取ARG参数内容
ENV APP_VERSION=${APP_VERSION}
ENV PATH /usr/local/nginx/sbin:$PATH
# ADD 从本地当前目录复制文件到容器. 文件放在当前目录下,拷过去会自动解压
# COPY 功能类似ADD,但是是不会自动解压文件,也不能访问网络资源
# 具体说明见下文
ADD nginx-1.8.0.tar.gz /usr/local/
ADD epel-release-latest-7.noarch.rpm /usr/local/
# 指定运行容器时的用户名或 UID,后续的 RUN 也会使用指定用户。可在不同位置进行切换
USER root
# USER user:group
# USER uid:gid
# RUN 构建镜像时执行的命令。每运行一条RUN,容器会添加一层,并提交
RUN rpm -ivh /usr/local/epel-release-latest-7.noarch.rpm
RUN yum install -y wget lftp gcc gcc-c++ make openssl-devel pcre-devel pcre && yum clean all
RUN useradd -s /sbin/nologin -M www
# WORKDIR 相当于cd
WORKDIR /usr/local/nginx-1.8.0
RUN ./configure --prefix=/usr/local/nginx --user=www --group=www --with-http_ssl_module --with-pcre && make && make install
RUN echo "daemon off;" >> /etc/nginx.conf
# EXPOSE 映射端口
EXPOSE 80
## ENTRYPOINT和CMD
# 共同点:都可以指定shell或exec函数调用的方式执行命令;当存在多个时,都是只有最后一个生效
# 不同点:CMD指令指定的容器启动时命令可以被docker run指定的命令覆盖,而ENTRYPOINT指令指定的命令不能被覆盖,而是将docker run指定的参数当做ENTRYPOINT指定命令的参数;CMD指令可以为ENTRYPOINT指令设置默认参数,而且可以被docker run指定的参数覆盖
# ENTRYPOINT ["executable", "param1", "param2"] # 如果需要执行shell命令,可为:ENTRYPOINT ["sh", "-c", "echo $PATH"]
# ENTRYPOINT command param1 param2 # 执行shell命令
# CMD ["executable","param1","param2"] # 使用 exec 执行,推荐方式
# CMD command param1 param2 # 在 /bin/sh 中执行,提供给需要交互的应用
# CMD ["param1","param2"] # 提供给 ENTRYPOINT 的默认参数
# CMD 构建容器后调用,也就是在容器启动时才进行调用
# CMD ["/bin/bash", "-c", "npm start && node ./server/server.js"]
CMD ["nginx"]
ADD/COPY
- 语法:
ADD <src>… <dest>
或者ADD ["<src>",… "<dest>"]
每个
<src>
可以包含通配符并且使用Go的filepath.Match
规则匹配1
2ADD hom* /mydir/ # adds all files starting with "hom"
ADD hom?.txt /mydir/ # ? is replaced with any single character, e.g., "home.txt"ADD遵守如下规则
<src>
路径必须在构建上下文内。不能ADD ../something /something
,因为docker build的第一步已经把上下文目录和子目录发送到docker daemon了- 如果
<src>
是一个目录,目录的所有内容都将复制,包括文件系统元数据,但是不包括目录本身 ADD http://example.com/foobar /test
将创建文件/test/foobar
- 如果
<src>
是一个本地的可识别的tar压缩文件(如gzip、bzip2或xz),那么将在容器内解压为目录。远程URL的压缩文件将不会解压 - 如果
<src>
是多个资源,不管是直接指定或使用通配符,那么<dest>
必须是一个目录,并且要以斜杠/结尾 - 如果
<dest>
不以斜杠/结尾,将视其为一个普通文件,<src>
的内容将写到这个文件 - 如果
<dest>
不存在,则会与其路径中的所有缺少的目录一起创建
- COPY 功能类似ADD,但是是不会自动解压文件,也不能访问网络资源
docker-compose 多容器控制 ^1
- docker-compose 是用来做docker的多容器控制,默认基于
docker-compose.yml
来进行配置 pip install docker-compose
安装(为python实现),可能需要提前安装pip:yum install python-pip
命令
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# 非管理员运行docker-compose命令(sudo执行),可能会提示ERROR: Couldn't connect to Docker daemon at http+docker://localhost - is it running?
Usage:
docker-compose [-f <arg>...] [options] [COMMAND] [ARGS...]
docker-compose -h|--help
Options:
-f, --file FILE Specify an alternate compose file (default: docker-compose.yml)
# eg: docker-compose -f my_docker-compose.yml up -d # 指定配置文件启动
-p, --project-name NAME Specify an alternate project name (default: directory name)
--verbose Show more output
--no-ansi Do not print ANSI control characters
-v, --version Print version and exit
-H, --host HOST Daemon socket to connect to
--tls Use TLS; implied by --tlsverify
--tlscacert CA_PATH Trust certs signed only by this CA
--tlscert CLIENT_CERT_PATH Path to TLS certificate file
--tlskey TLS_KEY_PATH Path to TLS key file
--tlsverify Use TLS and verify the remote
--skip-hostname-check Don't check the daemon's hostname against the name specified
in the client certificate (for example if your docker host
is an IP address)
--project-directory PATH Specify an alternate working directory (default: the path of the Compose file)
Commands:
build Build or rebuild services
bundle Generate a Docker bundle from the Compose file
config Validate and view the Compose file # 校验配置文件语法格式
create Create services
# 创建容器,之后执行start启动容器(docker-compose up -d则会自动创建和启动)
down Stop and remove containers, networks, images, and volumes
events Receive real time events from containers
exec Execute a command in a running container
help Get help on a command
images List images # 查看使用的镜像信息
kill Kill containers
logs View output from containers
# 获取日志(docker-compose logs [my_service_name]). **比docker logs的日志多一些,包含compose解析相关日志。只有容器重新创建日志才会清除**
pause Pause services
port Print the public port for a port binding
ps List containers # 查看运行的容器
pull Pull service images # 不管registry有没有更新,都会重新拉取此compose中镜像,历史镜像标签将会变成<none>,下次up启动则是使用新镜像
push Push service images
restart Restart services # 重启服务。**不管compose配置文件是否修改,重启都不会重新创建容器**
rm Remove stopped containers # 删除老旧的服务(docker-compose rm my_service_name)
run Run a one-off command
# docker-compose run my_service_name bash # 可进入到容器中,对于一些启动失败的可以通过此方式调试
scale Set number of containers for a service
start Start services # 启动服务(如docker-compose.yml有多个服务时,可以只运行其中一个,docker-compose start my_service_name)
stop Stop services # 停止服务,类似启动
top Display the running processes
unpause Unpause services
up Create and start containers
# 创建并启动容器(在docker-compose.yml文件所在目录执行)。-d 表示后台运行。当前用户需要在docker组或者使用root用户启动(如sudo)
# 多次执行up启动只会启动services中未运行的服务。如果修改了compose配置重新执行则会重新创建容器
# 重新启动容器不会有产生多的镜像或容器
-d
# docker-compose pull && docker-compose up -d # 强制更新镜像并重启
version Show the Docker-Compose version information
案例
docker-compose.yml
示例
1 | version: '3' # 表示使用第3代语法来构建 |
$VARIABLE
和${VARIABLE}
两种写法都支持,可以使用双美元符号($$
)来转义美元符号。如果使用的是2.1文件格式,还可以在一行中设置默认的值:${VARIABLE:-default}
当VARIABLE没有设置或为空值时使用default值${VARIABLE-default}
仅当VARIABLE没有设置时使用default值
容器启动先后顺序问题 ^7
depends_on
表示再启动容器时会先启动依赖的服务,但并不能控制等依赖启动完成才启动此服务- 基于
wait-for-it.sh
解决先后启动。脚本代码
同一 docker-compose 配置文件中的多个容器默认处于统一网络,不同 docker-compose 配置文件处于不同网络
- 每个 docker-compose 配置文件会产生一个xxx_default的网络(查看网络:docker network ls)
- 如果 docker-compose 配置文件(假如所在目录为mydir)中只有一个服务则默认生成
mydir_服务名_default
,如果有多个服务则会生成一个123456789_default
的网络 - 自定义网络、共用一个网络
1 | # 如果此yml文件所在目录为mydir |
- volumes使用同networks
1 | version: '3' |
配置参数
- Compose和Docker兼容性:Compose 文件格式有3个版本,分别为1, 2.x 和 3.x,目前主流的为 3.x 其支持 docker 1.13.0 及其以上的版本
1 | version: '3' # 指定 compose 文件的版本 |
常用docker镜像
docker hub
centos
docker run -itd --name centos centos:7
官方提供的centos镜像,无netstat、sshd等服务,测试可进行安装- 安装netstat:
yum install net-tools
- 安装sshd:
yum install openssh-server
,启动如下:mkdir -p /var/run/sshd
/usr/sbin/sshd -D &
ubuntu
docker run -itd --name ubuntu ubuntu:14.04
java:8-jre
一般是docker-compose中引入python:3.6
busybox
maven:3.6.0-jdk-8-alpine
docker:18.06.2-dind
自行编译jdk
- 如ofbiz等项目容器化,需要在容器中编译运行,自行编译jdk作为基础容器
- 在文件夹test下创建文件
Dockerfile
,并将jdk-7u80-linux-x64.tar.gz
复制进去
1 | FROM bzyep49h.mirror.aliyuncs.com/library/centos:7 |
- 打包及推送
1 | # 打包生成镜像(大概508M) |
nginx
1 | version: '3' |
- docker默认的nginx.conf配置为nginx.conf
- 宿主机上配置
$PWD/conf.d/test.conf
1 | server { |
- 更新配置说明
- 如果仅更新配置文件需要执行nginx加载命令重新加载配置文件
docker exec -it sq-nginx /usr/sbin/nginx -t
docker exec -it sq-nginx /usr/sbin/nginx -s reload
(未测试成功,但是进入到容器中重启可成功)
- 如果修改了compose配置文件执行上述命令会重新创建容器(不会拉取新的镜像)
- 如果仅更新配置文件需要执行nginx加载命令重新加载配置文件
mysql/mysql-server:5.7
- 容器中默认数据文件路径:
/var/lib/mysql
(下面配置已进行修改) - 下列配置产生的root用户为root@localhost,修改MYSQL_HOST/MYSQL_ROOT_HOST也无效。可进入容器后执行
mysql -hlocalhost -uroot -p
再进行修改 - 下列配置 ^9
- 需要先在docker-compose.yml所在目录创建好配置文件
my.cnf
- 如需执行初始化sql语句需先在docker-compose.yml所在目录创建好
init/init.sql
- 第一次初始化容器,会先启动mysql进行初始化,然后重新启动mysql。稍等片刻可通过
sudo docker logs sq-mysql
查看日志 - 第一次初始化容器完成后,可删掉容器重新初始化一次(无需清除mysql数据卷),防止MYSQL_ROOT_PASSWORD等敏感信息显示在容器信息中
- 需要先在docker-compose.yml所在目录创建好配置文件
1 | # docker-compose.yml |
1 | # /home/data/etc/mysql/my.cnf |
1 | -- /home/data/etc/mysql/init/init.sql |
tomcat
1 | # docker-compose.yml |
- 部署war
docker cp demo.war sq-tomcat:/usr/local/tomcat/webapps
- 重启容器
docker restart sq-tomcat
ftp服务器
stilliard/pure-ftpd ftp服务器 ^6
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## 安装启动
# 创建容器。默认数据端口30000-30009,只能满足5个用户同时FTP登陆。计算方式为"(最大端口号-最小端口号) / 2"。里修改为可以满足100个用户同时连接登陆
# /home/ftpusers为默认的用户数据目录;/etc/pure-ftpd为配置数据,包括用户登录信息(/etc/pure-ftpd/pureftpd.passwd);增加环境变量`-e "ADDED_FLAGS ..."`表示生成日志(未测试成功)
docker run -dt --name ftpd_server \
-p 21:21 -p 30000-30209:30000-30209 \
-v /home/data/docker/pure-ftpd/ftpusers:/home/ftpusers \
-v /home/data/docker/pure-ftpd/etc:/etc/pure-ftpd \
-e "ADDED_FLAGS=-d -d" \
stilliard/pure-ftpd:hardened bash
# 进入容器(exec在运行的容器中执行一条命令)
docker exec -it ftpd_server bash
# 创建用户输入密码并保存(会自动创建用户目录test,用户默认可在此目录增删改文件或文件夹)。ftpd运行时,可以进入容器添加用户,无需再重新启动
pure-pw useradd test -u ftpuser -d /home/ftpusers/test
pure-pw mkdb # 可添加完所有用户一次性保存
# 在容器中运行FTP。`-c 100`为允许同时连接的客户端数列100, `-C 100`为同一IP最大的连接数100, 这两个数值与端口号30000:30209对应上
/usr/sbin/pure-ftpd -c 100 -C 100 -l puredb:/etc/pure-ftpd/pureftpd.pdb -E -j -R -P $PUBLICHOST -p 30000:30209 &
## 管理相关
# 查看用户
cat /etc/pure-ftpd/pureftpd.passwd
# 更改test户名密码(pure-pw需要在容器中运行)
pure-pw passwd test
pure-pw mkdb # 保存
# 删除用户
pure-pw userdel test -f /etc/pure-ftpd/pureftpd.passwd
pure-pw mkdb
## 添加用户sh脚本
USER=$1
docker exec -dt ftpd_server pure-pw useradd $USER -u ftpuser -d /home/ftpusers/$USER
docker exec -dt ftpd_server pure-pw mkdb- 需要使用主动模式连接
- 常见问题
- 在文件管理其中连接服务器是,提示
打开ftp服务器上的文件夹时发生错误,请检查是否有权限访问该文件夹
:IE浏览器 - Internet选项 - 高级 - 去勾选”使用被动 FTP” - xftp 提示无法显示远程文件夹:点击属性->选项->将使用被动模式选项去掉即可
- 在文件管理其中连接服务器是,提示
安装私有仓库服务器 ^2
- Registry:docker仓库注册服务器,用于管理镜像仓库,起到的是服务器的作用
- Repository:docker镜像仓库,用于存储具体的docker镜像,起到的是仓库存储作用
命令安装方式
- docker-server(也可使用Harbor代替)
1 | ## 在docker-server上安装私有仓库 |
- docker-client
1 | ## 修改docker-client仓库地址 |
Harbor
- Harbor、github
- Harbor是基于GO开发的一个用于存储和分发Docker镜像的企业级Registry服务器(私有仓库),提供web界面访问,角色控制。其提供镜像复制功能:镜像可以在多个Registry实例中复制(同步),尤其适合于负载均衡,高可用,混合云和多云的场景 ^3
- 安装(内部包含一个registry服务器的安装)。基于helm安装参考helm.md#Harbor
1 | ## 安装docker-compose |
- harbor日志目录默认在
/var/log/harbor
,默认数据存储路径为/data
harbor.cfg
修改后,需要执行./prepare
(会在当前目录重新生成common文件夹。主要是配置信息,如nginx.conf,为docker-compose.yml中相关配置文件的映射)- 常见问题
- registry服务一直处于
restarting
,且日志/var/log/harbor/xxx/registry.log报错open /etc/registry/root.crt: no such file or directory
。主要是prepare源码有问题导致时没有生成文件/etc/registry/root.crt,具体参考https://www.cnblogs.com/breezey/p/9111894.html
- registry服务一直处于
Docker集群管理
- 轻量级的开源 docker 管理工具有
portainer
,重量级的有rancher
。如果服务不多,集群节点不多的话一般 portainer 足以胜任;如果是大型集群的话可以考虑 rancher
Docker远程TLS管理
- docker进程
- docker 容器进程:就是运行在 docker 容器中的应用进程,比如你用 docker 启动的 web 应用,数据库等
- docker 守护进程:docker 的设计是 C/S 模式,docker 守护进程运行在宿主机上,它默认监听
/var/run.docker.sock
(unix 域套接字)文件,本机的 docker 客户端是默认通过 /var/run.docker.sock 来与 docker 守护进程进行通信的
- 直接开启远程访问,无安全措施
dockerd -H 0.0.0.0
监听所有tcp连接,默认端口是6375。在systemd下,则需要修改docker.service的ExecStart- 在当前容器上可以执行另一容器的命令
docker -H tcp://192.168.6.131:6375 ps
- 安全的Docker访问(TLS)
启动SpringCloud应用
配置如下,需要启动的所有maven子项目都需要加下列配置 ^5
依赖
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<properties>
<docker_plugin_version>0.4.13</docker_plugin_version>
<!-- 此路径为如Harbor站点路径 -->
<docker_registry>192.168.17.196:10010</docker_registry>
<registry_project_name>shengqi</registry_project_name>
</properties>
<!--利用maven插件构建docker镜像-->
<plugin>
<groupId>com.spotify</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>${docker_plugin_version}</version>
<executions>
<!--设置在执行maven的package时构建镜像-->
<execution>
<id>build-image</id>
<phase>package</phase>
<goals>
<!--执行此插件的build指令,进行docker镜像构建-->
<goal>build</goal>
</goals>
</execution>
</executions>
<configuration>
<!--私有仓库配置,默认使用localhost:2375-->
<serverId>my-docker-registry</serverId><!-- 对应maven/setting.xml中的server,用于登录私有服务器 -->
<registryUrl>${docker_registry}</registryUrl>
<!--build完成后进行推送-->
<pushImage>true</pushImage>
<!-- 镜像名称。必须要先(在Harbor中)创建此项目且有对应项目的权限 -->
<imageName>${docker_registry}/${registry_project_name}/${project.artifactId}:${project.version}</imageName>
<imageTags>
<imageTag>latest</imageTag>
<imageTag>${project.version}</imageTag>
</imageTags>
<!-- 基于Dockerfile进行编译镜像(Dockerfile放在对应/src/main/docker目录下,如果放在父项目根目录则无法编译成功) -->
<dockerDirectory>${project.basedir}/src/main/docker</dockerDirectory>
<resources>
<resource>
<targetPath>/</targetPath>
<directory>${project.build.directory}</directory>
<include>${project.build.finalName}.jar</include>
</resource>
</resources>
</configuration>
</plugin>使用私有仓库时,需要配置登录私有仓库信息。配置maven的setting.xml文件
1
2
3
4
5
6
7
8
9
10<servers>
<server>
<id>my-docker-registry</id>
<username>admin</username>
<password>Harbor12345</password>
<configuration>
<email>test@aezo.cn</email>
</configuration>
</server>
</servers>src/main/docker/runboot.sh
1
2
3
4
5
sleep 15 # 按照先后顺序进行适当睡眠
# 此处不能通过 nohup 命令执行。nohup执行完成后会退出命令,此时容器会自动关闭掉
java -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/app/logs/jvmlogs/ -XX:+CrashOnOutOfMemoryError -Xmx512m -jar /app/app.jar- 必须在src/main目录,如果在项目源码目录之外则基于Dockerfile的ADD等命令会出错(Dockerfile中ADD命令写相对路径,会出现找不到文件)
- sh等文件需要是linux格式,否则容易报类似错误:
: No such file or directory: bash
src/main/docker/Dockerfile
1
2
3
4
5
6
7
8
9
10FROM java:8-jre
MAINTAINER smalle <oldinaction@qq.com>
# 无app文件夹时,会自动创建
ADD sq-eureka-0.0.1-SNAPSHOT.jar /app/app.jar
# ADD wait-for-it.sh /app/
ADD runboot.sh /app/
# RUN chmod +x /app/wait-for-it.sh
RUN chmod +x /app/runboot.sh
CMD /app/runboot.sh
# EXPOSE 9800 # 基于docker-compose则不需要
执行maven的package命令(会触发镜像build指令)。
- 需要本地(打包镜像的机器)启动docker服务,否则报错:
Exception caught: Timeout: GET https://192.168.99.100:2376/version
(此地址为windows环境变量DOCKER_HOST
配置的docker虚拟机地址) - 需要本地(打包镜像的机器)docker配置insecure-registries中加入registry路径,编辑文件
vi /etc/docker/daemon.json
。docker默认是基于https进行验证的,如果是http服务则需要配置此参数
- 需要本地(打包镜像的机器)启动docker服务,否则报错:
docker-compose.yml
镜像管理文件- 其中
EUREKA_HOST=sq-eureka
是因为服务运行在不同的容器中(尽管在一台docker虚拟机上),此处不能使用localhost,必须使用服务名进行通信。(docker-compose.yml写入中文会报错) ${COMPOSE_PROJECT_NAME:-local/shengqi/}
表示取环境变量COMPOSE_PROJECT_NAME的值,无则使用默认值local/shengqi/
(注意前面的-
),且默认值只适用于version: '3'
- 或者在
docker-compose.yml
文件所在目录创建.env
文件,里面定义环境变量如COMPOSE_PROJECT_NAME=192.168.17.196:10010/shengqi/
(.env文件适用于version: '2'
设置默认值。命令行中的环境变量 > .env文件中的环境变量 > Dockerfile文件) - 此时
COMPOSE_PROJECT_NAME
正好是docker-compose内置的环境变量,也可以通过docker-compose up -p my_project_name
的方式传入COMPOSE_PROJECT_NAME值
- 或者在
- 其中
1 | version: '3' |
- 启动:在
docker-compose.yml
目录下执行docker-compose up -d
- 访问:http://docker-host:9800
参考文章