总结docker一些常用到命令,数据卷, 网络管理,dockerfile ,docker-compose,容器监控等偏实战的内容,整理成一篇文章。
docker容器
- docker ps 列出运行的容器的信息
- docker create 创建容器
- docker start 启动容器
- docker run 运行容器,没有会创建
- docker attach
- docker attach 让我们可以进入到一个运行着的容器的内部,这个命令的原理是给一个正在运行的容器分配一个 stdin、stdout 和 stderr。
- docker exec
- exec 命令的用处是在一个运行着的容器里面执行一个命令。关于这个命令的原理其实很简单,在 Linux 内核层面,相当于 fork 了一个进程,然后这个进程设置和容器相同的 NameSpace。如果我们 OPTIONS 指定 -ti ,那么我们就可以进入到一个运行着的容器里面执行命令了。因为这个是一个 fork 出来的进程,所以可以 exit。
- docker pause 容器暂停
- docker pause 容器取消暂停 恢复容器
- docker restart 重启容器
- docker stop 关闭容器
- docker kill 终止容器
- docker rm 删除容器
- -f 强制删除运行的容器
- docker commit 基于容器创建镜像
- docker commit -m “改动信息” -a “作者信息” [container_id] [new_image:tag]
- docker export [容器id] > 模板文件名.tar 基于容器创建镜像
- docker import 导入文件变成镜像
- cat nginx.tar | docker import - [image:tag]
- docker logs 运行日志
- docker logs -n xxxx 看几行
- docker logs -f xxx = tail -f 一样的效果
- docker inspect
- docker inspect –format=’{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}’
container-id
- docker inspect –format=’{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}’
- docker port 查看容器端口信息
- docker rename 容器重命名
- ocker container prune 清理处于停止状态的容器
- docker top 进程相关信息,进程号,父id ,cmd,运行时间
生产方式进入容器
1#!/bin/bash
2
3# chmod +x docker_in.sh
4# 记得装上 nsenter 这个工具
5#定义进入仓库函数
6docker_in(){
7 NAME_ID=$1
8 PID=$(docker inspect --format {{.State.Pid}} $NAME_ID)
9 nsenter --target $PID --mount --uts --ipc --net --pid
10}
11docker_in $1
进入指定的容器
1./docker_in.sh `container_id`
docker镜像
- docker images:列出本地所有的镜像;
- docker build:通过 Dockerfile build 出镜像;
- docker commit:将容器中的所有改动生成新的镜像;
- docker history:查看镜像的历史;
- docker save:将镜像保存成 tar 包;
- docker import:通过 tar 包导入新的镜像;
- docker load:通过 tar 包或者标志输入导入镜像;
- docker rmi:删除本地镜像;
- docker tag:给镜像打 tag。
- docker search 搜索远程仓库镜像
- docker image inspect
- docker cp xxx.txt [container_id|name]:/ copy
cat 模板文件名.tar | docker import - [自定义镜像名]
- docker image prune -a 清理无容器使用的镜像
docker镜像仓库
- docker pull 拉取镜像
- docker tag 镜像重命名
- docker tag busybox registry.cn-hangzhou.aliyuncs.com/xxx/demo:v1
- login 登陆仓库
- docker login –username=xxx registry.cn-hangzhou.aliyuncs.com
- docker push 推送镜像到仓库
- docker push registry.cn-hangzhou.aliyuncs.com/xxx/demo:v1
- docker logout 登出镜像仓库
docker 仓库,客户端默认以https形式, 如果要http方式,需要设置不安全的仓库配置 "insecure-registries": ["xxx.com:5000"]
docker数据卷的使用
如果我们想要在 Docker 容器停止之后创建的文件依旧存在,也就是将文件在宿主机上保存。那么我们有两种方式:volumes、bind mounts。
如果 Docker 是运行在 Linux 系统上,那么我们还可以使用 tmpfs;对应在 Windows 系统上,可以使用 named pipe (这个不做讨论)。
- Volumes 会把文件存储到宿主机的指定位置,在 Linux 系统上这个位置为
/var/lib/docker/volumes/
。这些文件只能由 Docker 进程进行修改,是 docker 文件持久化的最好的方式。 - bind mounts 可以将文件存储到宿主机上面任意位置,而且别的应用程序也可以修改。
- tmpfs 只会将数据存储到宿主机的内存中,并不会落盘。
volumes
Volumes 由 Docker 创建和管理。我们可以通过命令 docker volume create
显式地创建 volume,也可以由 Docker 进程在需要的时候自动创建,比如服务初始化的时候。
当我们创建一个 volume 之后,这个 volume 的数据会存储在宿主机的指定目录。然后我们可以将这个 volume 挂载到容器内部,然后我们就可以在容器内部的对应挂载点访问这个 volume。这种挂载的方式和 bind mounts 很相似,区别在于 volume 只能由 Docker 进程管理。
同一个 volume 可以同时挂载到多个容器内部。Docker 并不会在没有容器使用 volume 的时候自动删除该 volume,我们可以通过命令 docker volume prune
来移除指定的 volume。
Volume 相比 bind mounts 的优点包括:
- 更容易做数据备份和迁移
- 可以使用 Docker CLI 或者 Docker API 管理 volume
- Volume driver 可以让我们使用远端存储
- 可以在容器间共享和重用
相比将数据保存在容器的写入层,volume 是一种更好的数据持久化方式。因为 volume 不会增加容器的大小,同时 volume 的数据存活独立于容器的生命周期。
创建一个名字叫做 test
的 volume
1[root@aliyun volumes]$docker volume create test
2test
3[root@aliyun volumes]$pwd
4/var/lib/docker/volumes
5[root@aliyun volumes]$ls
6...
7ad75dba6b4fb5bafd480d4d3435ed4a7d6071dae86e57a1e0227b1bee2c7430f
8f625bc82e08ed43e23dde59fc5b8f1432994cb577d01fd16fd8f83e3ef1ef4bc
9metadata.db
10test
删除 volume
1docker volume rm test
可以通过参数 -v/--volume
和 --mount
来使用 volume。这两个参数在设计之初区别在于:-v/--volume
用于单个容器;而 --mount
用于 swarm service。但是,在 Docker 17.06 版本之后,对于单个容器应用也可以使用 --mount
参数。下面是两个参数的使用示例
1docker run -d \
2 --name devtest \
3 -v test:/app \
4 nginx:latest
1docker run -d \
2 --name devtest \
3 --mount source=test,target=/app \
4 nginx:latest
docker 会自动帮我们创建出数据卷
1 docker run -d --name devtest -v myvol2:/app nginx:latest
2 [root@aliyun volumes]$ls
3f625bc82e08ed43e23dde59fc5b8f1432994cb577d01fd16fd8f83e3ef1ef4bc
4metadata.db
5myvol2
6test
介绍一下这两个参数的异同
-v/--volume
参数包含三个字段,以冒号分隔,顺序相关:
- 第一个字段是 volume 的名字,单台宿主机上 volume 名字唯一,如果是匿名的 volume,第一个字段可以忽略
- 第二个字段是容器内的挂载点
- 第三个字段是以逗号分隔开的一系列的可选参数
--mount
参数包含一系列的 key-value 对,以逗号分隔,
比如 'type=volume,src=<VOLUME-NAME>,dst=<CONTAINER-PATH>,volume-driver=local
-
type : 挂载介质的类型,可以是
bind
、volume
和tmpfs
-
source:volume 名字,也可以简写为 src。
-
destination :容器内的挂载点,可以简写为 dst,或者 target。
-
readonly:可选的,如果添加则表示该 volume 是只读的。下面这个例子就是一个只读的例子。
1$ docker run -d \ 2 --name=nginxtest \ 3 --mount source=nginx-vol,destination=/usr/share/nginx/html,readonly \ 4 nginx:latest
-
volume-opt:其他可选参数。
下面是一个
--mount
的例子。
1docker service create \
2 --mount 'type=volume,src=<VOLUME-NAME>,dst=<CONTAINER-PATH>,volume-driver=local,volume-opt=type=nfs,volume-opt=device=<nfs-server>:<nfs-path>,"volume-opt=o=addr=<nfs-address>,vers=4,soft,timeo=180,bg,tcp,rw"'
3 --name myservice \
4 <IMAGE>
总体来说这两个参数支持选项和功能基本一致,区别在于运行一个 service 的时候,只能使用 --mount
。
最佳实践
volume 的最佳使用场景如下:
- 在多个容器间共享数据。volume 不会随着容器停止而被删除,只能够被显示的删除。
- 使用 volume 来保存一些配置信息,可以达到数据解耦的目的。
- 借助于 volume driver,可以将数据存储到远端机器或者云平台上。
- 数据备份、迁移等场景。我们只需要备份目录
/var/lib/docker/volumes/<volume-name>
。
bind mounts
bind mounts 模式与第一种 volume 非常类似,区别在于宿主机的文件位置不是固定在 /var/lib/docker/volumes/
目录下,而是宿主机上面的任意目录。这也就意味着数据可以被任意程序改动。
另外当容器内部的挂载目录非空时,bind mounts 和 volume 还有一些行为的差异:
- 使用 volume 时,这个容器目录中的文件会被复制到 volume中,也就是说容器目录原有文件不会被 volume覆盖。
- 使用 bind mounts 时,容器目录中原有的文件会被隐藏,从而只能读取到宿主机目录下的文件。
如何使用
使用和 volume 的使用非常类似,区别在于对于 bind mounts ,source 指定的是宿主机的目录,而不是 volume 的名字。
最佳实践
一般情况下,我们要尽可能的使用 volume。下面几种情况可以考虑使用 bind mounts。
- 在宿主机和容器之间共享配置。比如容器默认挂载宿主机的文件
/etc/resolv.conf
来实现 DNS 解析。 - 在宿主机和容器之间共享代码或者可执行文件。比如,将一个 maven 的
target/
目录挂载到容器内,这样每次我们在宿主机上编译完,容器内部就能得到最新的文件。
tmpfs
tmpfs 只支持 Linux,不会将数据持久化到宿主机或者容器内部的文件系统上。在容器的生命周期内,数据将会保存在宿主机的内存里,一旦容器停止,数据将会被删除。和 volume 不同的是,每个容器关联的 tmpfs 不能够共享。
如何使用
可以通过两个参数 --tmpfs
和 --mount
来使用 tmpfs 。在设计之初,--tmpfs
参数是给单个容器作为参数使用的,--mount
参数用在 swarm 中。但是在 Docker 17.06 版本之后,--mount
参数也可以用在单个容器,而且 --mount
参数也会更加的直观。下面是两种使用示例:
1docker run -d \
2 -it \
3 --name tmptest \
4 --tmpfs /app \
5 nginx:latest
6
7docker run -d \
8 -it \
9 --name tmptest \
10 --mount type=tmpfs,destination=/app,tmpfs-mode=1770 \
11 nginx:latest
--tmpfs
不能指定额外参数,--mount
针对 tmpfs 提供了额外的可选参数:
- tmpfs-size: 指定 tmpfs 的大小,默认不受限制,单位 byte
- tmpfs-mode:Linux 系统的文件模式,比如 700;默认值为 1777,也就是任何用户都可以写。
最佳实践
tmpfs 的最佳使用场景是不希望数据持久化到容器文件系统或者宿主机上。比如出于安全考虑,将一些认证信息存储到 tmpfs 中,或者出于性能考虑,将一些 state 信息存储在内存中,同时又不需要持久话。
使用 Dockerfile 添加 volume
在 dockerfile 的语法中可以通过 VOLUME
创建一个 volume 或者多个 volume。
1#创建一个 volume
2VOLUME /data
3# 创建多个 volume
4VOLUME ["/data1", "/data2"]
演示
1FROM busybox:latest
2VOLUME /data
1[root@docker dockerfile2]# docker build -t volume-image:v1 .
2Sending build context to Docker daemon 5.12kB
3Step 1/2 : FROM busybox:latest
4 ---> 6d5fcfe5ff17
5Step 2/2 : VOLUME /data
6 ---> Running in c74eeadfbf3f
7Removing intermediate container c74eeadfbf3f
8 ---> 71d5c091d1c0
9Successfully built 71d5c091d1c0
10Successfully tagged volume-image:v1
11[root@docker dockerfile2]# docker images | grep volume-image
12volume-image v1 71d5c091d1c0 13 seconds ago 1.22MB
13[root@docker dockerfile2]#
创建 volume 之后,Docker 会在容器启动时挂载一个 volume 到挂载点 /data
。如果镜像中存在目录 /data
,则这个文件夹中的文件都将全部被复制到宿主机中 volume 对应的文件夹中,一般位于目录 /var/lib/docker/volumes/
。
在 Dockerfile 中使用 volume 有一点需要注意的是,由于 volume 只有在容器创建的时候才会挂载进来,所以如果我们在 Dockerfile 中尝试将 volume 作为一个目录并做一下操作,这个是不会生效的,原因就是在当前镜像中这个文件夹还不存在。比如如下的操作:
1VOLUME /data
2RUN touch /data/file
正确做法是先创建该目录,执行我们需要的操作,最后添加 volume。
1RUN mkdir /data
2RUN touch /data/file
3VOLUME /data
volume 共享
volume 共享可以通过参数 --volumes-from
实现。我们在上面启动了一个带有 volume 的容器,我们下面启动一个新的容器共享之前的 volume。
1[root@docker ~]# docker ps | grep volume-image:v1
212be76fd253e volume-image:v1 "sh" 20 minutes ago Up 20 minutes modest_lumiere
3[root@docker ~]# docker run -ti --volumes-from modest_lumiere busybox:latest sh
4/ # ls
5bin data dev etc home proc root sys tmp usr var
6/ #
我们可以看到新创建出来的 Docker 容器也有了目录 /data
,在之前的容器中 /data 下创建一个文件,新的容器中也会出现这个文件
也可以通过 docker inspect
查看这两个 Docker 容器中的 Mount 中的 volume 信息是不是相同即可。
volume 备份与迁移
volume 的数据的存储位置:
- 容器内的指定挂载点
- 宿主机的
/var/lib/docker/volumes
这两者的关联可以通过 docker inspcet
来查看,那么我们备份的话是备份那部分数据呢?其实都可以。官方建议备份容器内的指定挂载点的数据,好处是可以通过自动化或者说程序化的方式来备份,也就是下面的命令。
1$ docker run --rm --volumes-from dbstore -v $(pwd):/backup busybox tar cvf /backup/backup.tar /data
这行命令有以下几个作用:
-
启动一个工具容器 busybox,和目标容器共享 volume
-
将宿主机的当前目录和容器的目录
/backup
做映射 -
将共享的 volume 的挂载点的数据压缩拷贝到容器内部的目录
/backup
这样通过三步操作就将原容器中的 volume 数据备份到宿主机上了。对应的我们可以通过下面的命令将备份的数据进行恢复,这里就不再解释了。
1$ docker run --rm --volumes-from dbstore2 -v $(pwd):/backup ubuntu bash -c "cd /dbdata && tar xvf /backup/backup.tar --strip 1"
docker网络管理
docker网络类型
1: none
2: bridge (默认)
3.联盟式网络
- A,B容器 的命名空间(namespace),只隔离了 user,pid,amout ,共享network,ipc,uts
- 容器a和b 可以通过lo 进行通信即127.0.0.1
4.host 和宿主机用相同的网卡
5.overlay
这种模式在多个 Docker daemon 主机之间创建一个分布式网络,该网络位于 Docker 主机层次之上,允许容器之间加密通讯,需要处理容器之间和主机之间的网络包
适用于运行在多个宿主机上 Docker 容器之间的通信情况。
1docker info | grep Network
2# Network: bridge host ipvlan macvlan null overlay
指定端口映射
1#命令格式:
2docker run -d -p [宿主机ip]:[宿主机端口]:[容器端口] --name [容器名字][镜像名称]
3#注意:
4#如果不指定宿主机ip的话,默认使用 0.0.0.0,
5#命令实践: #现状我们在启动容器的时候,给容器指定一个访问的端口 1199
6docker run -d -p 192.168.8.14:1199:80 --name nginx-2 nginx
7docker run -d -p 80 --name nginx-3 nginx # 随机映射到主机的端口上去
多端口映射方法
1docker run -d -p [宿主机端口1]:[容器端口1] -p [宿主机端口2]:[容器端口2] --name [容器名称][镜像名称]
一些网络相关命令
1iptables -t -nat -vnL
2
3 # 查看tcp链接的端口号
4netstat -ntlp
5
6# 查看bridge的网络内部信息
7docker network inspect bridge
8
9# 查看当前主机网络
10docker network ls
11
12# 查看容器网络信息
13docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' `容器id`
14
15# 查看容器端口信息
16docker port [容器id]
–hostname, –dns, –dns-search,–add-host
如果用户想要手动指定容器的配置,可以在使用 docker run
命令启动容器时加入如下参数:
-h HOSTNAME
或者 --hostname=HOSTNAME
设定容器的主机名,它会被写到容器内的 /etc/hostname
和 /etc/hosts
。但它在容器外部看不到,既不会在 docker container ls
中显示,也不会在其他的容器的 /etc/hosts
看到。
--dns=IP_ADDRESS
添加 DNS 服务器到容器的 /etc/resolv.conf
中,让容器用这个服务器来解析所有不在 /etc/hosts
中的主机名。
--dns-search=DOMAIN
设定容器的搜索域,当设定搜索域为 .example.com
时,在搜索一个名为 host 的主机时,DNS 不仅搜索 host,还会搜索 host.example.com
。
--add-host "hostname:ip"
那么/etc/hosts 会增加对应的ip hostname 行
联盟式网络
1docker run --name b1 -it --rm busybox
2docker run --name b2 --network container:b1 -it --rm busybox # 那么 b1,b2 共用同一网络
配置docker守护进程
配置docker守护进程的属性信息的方法:/etc/docker/daemon.json 每一个可设置的键是dockerd的可用的选项,其值为选项的参数;但有些参数不可用于此文件中,例如add-registry
有些选项的参数是数组的格式,需要放置于[];
1{
2 "authorization-plugins": [],
3 "data-root": "",
4 "dns": [],
5 "dns-opts": [],
6 "dns-search": [],
7 "exec-opts": [],
8 "experimental": false,
9 "features":{},
10 "storage-driver": "",
11 "storage-opts": [],
12 "labels": [],
13 "log-driver": "",
14 "mtu": 0,
15 "pidfile": "",
16 "cluster-store": "",
17 "cluster-advertise": "",
18 "max-concurrent-downloads": 3,
19 "max-concurrent-uploads": 5,
20 "shutdown-timeout": 15,
21 "debug": true,
22 "hosts": [],
23 "log-level": "",
24 "tlsverify": true,
25 "tlscacert": "",
26 "tlscert": "",
27 "tlskey": "",
28 "swarm-default-advertise-addr": "",
29 "group": "",
30 "default-ulimits": {},
31 "bridge": "",
32 "fixed-cidr": "",
33 "raw-logs": false,
34 "allow-nondistributable-artifacts": [],
35 "registry-mirrors": [],
36 "insecure-registries": []
37}
dockerd守护进程的C/S,其默认仅监听Unix SOcket格式的地址,/var/run/docker.sock;
如果使用TCP套接字, /etc/docker/daemon.json: “hosts”: [“tcp://0.0.0.0:2375”, “unix:///var/run/docker.sock”]
也可向dockerd直接传递“-H|–host”选项;
远程连接使用方式
1docker -H xxxx:2375 image ls
自定义docker0桥的网络属性信息
自定义docker0桥的网络属性信息:/etc/docker/daemon.json文件
1{
2 "bip": "192.168.1.5/24",
3 "fixed-cidr": "10.20.0.0/16",
4 "fixed-cidr-v6": "2001:db8::/64",
5 "mtu": 1500,
6 "default-gateway": "10.20.1.1", # docker0 的默认网关
7 "default-gateway-v6": "2001:db8:abcd::89",
8 "dns": ["10.20.1.2","10.20.1.3"] # 至多3个,再多也没用
9}
核心选项为bip,即bridge ip之意,用于指定docker0桥自身的IP地址;其它选项可通过此地址计算得出。
1{
2 "bip": "192.168.1.5/24", #其他可以不改
3}
自定义网络
1docker network create -d bridge --subnet "172.26.0.0/16" --gateway "172.26.0.1" mybr0
2# 会创建一个虚拟网络接口
3docker network ls
4ifconfig # 查看 (新增一个网络接口)
5# 重命名 网络接口名
6ip link set dev 新增的网络接口名 name new_name(如docker1)
自定义网络,docker0 和自己新建的docker1 不在同一网段,默认是不给通信了。和iptables 设置有关,iptables 阻止了
容器间网络通信 –link 原理
做了link后 host文件,环境变量,以及iptables规则发生改变。
Link 使用
1docker run -d -e MYSQL_ROOT_PASSWORD=123456 -p 3307:3306 --name mysql mysql:latest
2e47e603ffb17f4b42d8841ff26d3b93935eed4cb4e3155ae901c0a3afce37b45
1[root@docker1 ~]# docker run -ti --name busybox --link mysql:mysql busybox:latest sh
2/ # telnet mysql
3telnet: can't connect to remote host (172.17.0.2): Connection refused
4/ # telnet mysql 3306
5Connected to mysql
6J
7�1.1jJXq/%
8 p@R|Iccaching_sha2_password
–link 的参数格式为 --link <name or id>:alias
,第一个参数是目标容器的名字或者 ID,第二个 alias 相当于在 busybox Docker 容器中访问 MySQL Docker 容器的 host
看busybox容器的hosts文件 多了 mysql一行
1/ # cat /etc/hosts
2127.0.0.1 localhost
3::1 localhost ip6-localhost ip6-loopback
4fe00::0 ip6-localnet
5ff00::0 ip6-mcastprefix
6ff02::1 ip6-allnodes
7ff02::2 ip6-allrouters
8172.17.0.2 mysql e47e603ffb17
9172.17.0.3 d73dc6529032
当两个容器通过 –link 建立连接后,会在接收容器中额外设置一些环境变量以保存源容器的一些信息
可以用env命令看一下busybox的容器,有好多mysql的环境变量
iptables-save 查看filter规则
1-A DOCKER -s 172.17.0.2/32 172.17.0.3/32 -i docker0 -o docker0 -p tcp -m tcp --dport 3306 -j ACCEPT
2-A DOCKER -s 172.17.0.3/32 172.17.0.2/32 -i docker0 -o docker0 -p tcp -m tcp --dport 3306 -j ACCEPT
这两条规则确保了我们的 busybox 容器在源容器(MySQL 容器)的 tcp/3306 端口上通信的流量不会被丢掉,从而保证了接收容器可以顺利地从源容器中获取到想要的数据。
容器监控
docker stats
显示的资源使用主要包括 CPU、内存、网络 IO、磁盘 IO 等。
1docker stats
2
3docker stats [OPTIONS] [CONTAINER...]
cAdvisor
Google 出品的专门用来监控 Docker 的工具;
1docker run \
2 --volume=/:/rootfs:ro \
3 --volume=/var/run:/var/run:rw \
4 --volume=/sys:/sys:ro \
5 --volume=/var/lib/docker/:/var/lib/docker:ro \
6 --publish=8081:8080 \
7 --detach=true \
8 --name=cadvisor \
9 google/cadvisor:latest
Kubernetes 中就自动集成了 cAdvisor
Dockerfile
Dockerfile创建镜像的基本步骤
- 查找dockerfile
- 查找当前路径以及上级路径的子目录
- 如果没有可以通过-f进行指定
- 将该路径下所有数据作为上下文发送给docker服务端
- 服务端校验Dockerfile
- 逐条执行Dockerfile中的指令
- 在执行指令的过程中,碰到ADD、COPY、RUN指令会生成一层新的镜像
- 返回最终镜像的生成ID
Dockerfile 使用准则
- 1、大: 首字母必须大写D
- 2、空: 尽量将Dockerfile放在空目录中。
- 3、单: 每个容器尽量只有一个功能。
- 4、少: 执行的命令越少越好。
Dockerfile 分为四部分
- 基础镜像信息
- 维护者信息
- 镜像操作指令
- 容器启动时执行指令
Dockerfile常用指令
指令 | 解释 |
---|---|
FROM | Dockerfile 除了注释第一行必须是 FROM ,FROM 后面跟镜像名称,代表我们 要基于哪个基础镜像构建我们的容器。 |
RUN | RUN 后面跟一个具体的命令,类似于 Linux 命令行执行命令。 |
ADD | 拷贝本机文件或者远程文件到镜像内 |
COPY | 拷贝本机文件到镜像内 |
USER | 指定容器启动的用户 |
ENTRYPOINT | 容器的启动命令 |
CMD | CMD 为 ENTRYPOINT 指令提供默认参数,也可以单独使用 CMD 指定容器启动参数 |
ENV | 指定容器运行时的环境变量,格式为 key=value |
ARG | 定义外部变量,构建镜像时可以使用 build-arg = 的格式传递参数用于构建 |
EXPOSE | 指定容器监听的端口,格式为 [port]/tcp 或者 [port]/udp |
WORKDIR | 为 Dockerfile 中跟在其后的所有 RUN、CMD、ENTRYPOINT、COPY 和 ADD 命令设置工作目录。 |
nginx镜像示例
1FROM ubuntu:22.04
2
3LABEL maintainer="cr-mao <cr-mao@qq.com>"
4
5## 下载加速
6#ADD sources.list /etc/apt/sources.list
7
8RUN apt update && apt install -y iproute2 ntpdate tcpdump telnet traceroute nfs-kernel-server nfs-common lrzsz tree openssl libssl-dev libpcre3 libpcre3-dev zlib1g-dev ntpdate tcpdump telnet traceroute gcc openssh-server lrzsz tree openssl libssl-dev libpcre3 libpcre3-dev zlib1g-dev ntpdate tcpdump telnet traceroute iotop unzip zip make
9
10ADD nginx-1.22.1.tar.gz /usr/local/src/
11RUN cd /usr/local/src/nginx-1.22.1 && ./configure --prefix=/apps/nginx && make && make install && ln -sv /apps/nginx/sbin/nginx /usr/bin
12RUN groupadd -g 2088 nginx && useradd -g nginx -s /usr/sbin/nologin -u 2088 nginx && chown -R nginx.nginx /apps/nginx
13ADD nginx.conf /apps/nginx/conf/
14
15
16EXPOSE 80 443
17
18
19## 通过 ENTRYPOINT 的方式启动nginx
20#ENTRYPOINT ["/apps/nginx/sbin/nginx","-g","daemon off;"]
21
22## 通过 ENTRYPOINT + CMD 的方式启动nginx , CMD 会作为 ENTRYPOINT 的执行参数。
23#ENTRYPOINT ["/apps/nginx/sbin/nginx"]
24#CMD ["-g","daemon off;"]
25
26## 通过启动脚本方式启动nginx
27COPY docker-entrypoint.sh /docker-entrypoint.sh
28RUN chmod a+x /docker-entrypoint.sh
29ENTRYPOINT ["/docker-entrypoint.sh"]
sources.list
1# 默认注释了源码镜像以提高 apt update 速度,如有需要可自行取消注释
2deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy main restricted universe multiverse
3# deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy main restricted universe multiverse
4deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy-updates main restricted universe multiverse
5# deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy-updates main restricted universe multiverse
6deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy-backports main restricted universe multiverse
7# deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy-backports main restricted universe multiverse
8deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy-security main restricted universe multiverse
9# deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy-security main restricted universe multiverse
docker-entrypoint.sh
1#!/bin/bash
2/apps/nginx/sbin/nginx -g "daemon off;"
构建命令
1docker build -t local/ubuntu-nginx:v0.0.1 -f dockerfile .
Dockerfile构建缓存
1docker build --no-cache -t [镜像名]:[镜像版本][Dockerfile位置]
exec “$@”
很多开源项目有用这个
1FROM nginx:1.14-alpine
2ARG author="cr-mao <cr-mao@qq.com>"
3LABEL maintainer="${author}"
4ENV NGX_DOC_ROOT="/data/web/html"
5ADD entrypoint.sh /bin/
6# 检测
7# HEALTHCHECK --start-period=3s CMD wget -O - -q http://${IP:-0.0.0.0}:${PORT:-80}/
8CMD ["/usr/sbin/nginx","-g","daemon off;"] # 作为 ENTRYPOINT 参数
9ENTRYPOINT ["/bin/entrypoint.sh"]
entrypoint.sh
1#!/bin/sh
2
3cat > /etc/nginx/conf.d/www.conf <<EOF
4server {
5 server_name ${HOSTNAME};
6 listen ${IP:-0.0.0.0}:${PORT:-80};
7 root ${NGX_DOC_ROOT:-/usr/share/nginx/html};
8
9}
10EOF
11# echo "$@" 进过验证$@ 就是 /usr/sbin/nginx -g daemon off;
12exec "$@"
13# 等价 exec "/usr/sbin/nginx -g daemon off; " 这个是不会生成
两阶段构建
1FROM golang:1.18.5-alpine3.15 AS base
2ENV CGO_ENABLED=0 GOOS=linux GO111MODULE=on GOPROXY=https://goproxy.cn
3WORKDIR /app
4COPY go.mod go.sum /app/
5RUN go mod download
6COPY . $WORKDIR
7RUN go build -o /usr/local/bin/gosky main.go && go clean -cache
8
9FROM alpine:3.15
10COPY --from=base /usr/local/bin/gosky /usr/local/bin/
11COPY local.config.yaml /
12COPY production.config.yaml /
13COPY testing.config.yaml /
1docker run -d --name gosky -p 8080:8080 gosky:v1.0.0 gosky serve --env=production
health check
有时候我们用别人的镜像跑起来的容器会有个状态,先是starting,后是healthy,也可能是unhealthy。 其实就是用的这个指令实现的
动由此Dockerfile创建的image的container时,docker会把当前container标记为starting, 直到curl –fail http://localhost:8080/heartbeat返回正确的值。
1.
2.
3HEALTHCHECK --interval=30s --timeout=30s --retries=120 CMD curl --fail http://localhost:8080/heartbeat || exit 1
4.
5.
docker-compose
用来编排单机容器,xxx.yml 文件遵循yaml格式
下载地址 https://github.com/docker/compose/releases/tag/v2.12.2
常用命令
1docker-compose -f xxx.yml up -d # 指定文件
2docker-compose up # 起来
3docker-compose up -d # 后台起来
4docker-compose down # 卸载容器和网络
5docker-compose ps # 查看容器状态
6docker-compose stop <服务名>
7docker-compose restart <服务名> # 重启
8docker-compose start <服务名>
9docker-compose rm #删除服务
10docker-compose logs -f #查看运行日志
一个比较全的示例
1#能够编排管理3个容器,php,redis,nginx
2version: "3.6"
3services: #服务
4 nginx1:
5 image: nginx #指定镜像名称
6 container_name: nginx1 #容器名称
7 ports: #端口映射
8 - "8089:80"
9 environment: #设置环境变量
10 password: "123456"
11 extra_hosts:
12 - "test:192.168.3.3"
13 networks:
14 redis-network:
15 ipv4_address: 192.168.1.8 #设置ip地址
16 depends_on:
17 - php1
18 stdin_open: true
19 volumes:
20 - /usr/docker/test/07/nginx/conf:/conf
21 privileged: true #特殊权限
22 working_dir: /conf #工作目录
23 php1:
24 #build:
25 # context: .
26 # args:
27 # test: 1
28 image: php-fpm
29 container_name: php-fpm1
30 networks:
31 redis-network:
32 ipv4_address: 192.168.1.7 #设置ip地址
33 working_dir: /www #工作目录
34 links:
35 - redis
36 volumes:
37 - /usr/docker/test/07/php/www:/www
38 stdin_open: true #打开标准输入
39 tty: true #模拟伪终端
40 ports:
41 - "9008:9000"
42 redis:
43 image: redis
44 container_name: redis1
45 networks:
46 redis-network:
47 ipv4_address: 192.168.1.6 #设置ip地址
48 working_dir: /usr/src/redis #工作目录
49 stdin_open: true
50 tty: true
51 ports:
52 - "6399:6379"
53 volumes:
54 - /usr/docker/test/07/redis/master:/usr/src/redis
55#设置网络环境
56networks:
57 #自定义网络
58 nginx:
59 driver: bridge
60 ipam:
61 config:
62 - subnet: "172.16.238.0/24"
63 #引用外部预先定义好的网段
64 redis-network:
65 external:
66 name: redis-network
links
- https://www.cntofu.com/book/139/network/dns.md
- https://docs.docker.com/engine/reference/commandline/dockerd/#run-multiple-daemons
- https://docs.docker.com/engine/userguide/networking/default_network/custom-docker0/
- https://docs.docker.com/compose/
- https://xie.infoq.cn/article/5a83c6a91c6fa763ff5227ccb