容器和物理机直接运行相比缺点
1性能
2隔离性,管理不方便 docker exec
3排错方法:docker logs;docker exec; docker 前台运行;docker ps -a ;cat /var/log/syslog;message
上期·总览
FROM 指定
LABEL 标签
ENV 变量
COPY 复制 解压打包在可
ADD 复制
RUN 运行Linux命令
ENTRYPOINT ["init.sh"] 和CMD相似金蝉推敲 ,通常用于初始化环境 脚本
CMD ["app"] 第2遍运行
EXPOSE 80 声明 docker run -P xxxxx:80 docker run -p xxx:yyy 端口声明,P默认引用p盖
目录
修改默认docker0(172.17.0.1)网桥的网络配置
无聊小知识:修改iptables实现同一宿主机上的不同网络的容器间通信
添加静态路由和iptables规则 (生产中没法用讲原理而已)
FROM: 指定基础镜像
定制镜像,需要先有一个基础镜像,在这个基础镜像上进行定制。
FROM 就是指定基础镜像,此指令通常必需放在Dockerfile文件第一个非注释行。后续的指令都是运行于此基准镜像所提供的运行环境
ARG CODE=22.04-20221017-v1.0
FROM ubuntu:${CODE}
ENV VERSTON="1.22.0"
ENV NGINX_INSTALL_DIR="/web/nginx"
LABEL Author=weizhaohui version=nginx-${VERSTON}
VOLUME: 匿名卷
在容器中创建一个可以从本地主机或其他容器挂载的挂载点,一般用来存放数据库和需要保持的数据等,默认会将宿主机上的目录挂载至VOLUME 指令指定的容器目录。即使容器后期被删除,此宿主机的目录仍会保留,从而实现容器数据的持久保存
名字乱码没啥用,有比没有好
/var/lib/docker/volumes/<volume_id>/_data
没运行时
- 重新运行后,多了一个备份,名字为随机乱码,再次创建只会生成新的 docker rm -vf xx 加v就可以把他删了
WORKDIR: 指定工作目录
为后续的 RUN、CMD、ENTRYPOINT 指令配置工作目录,当容器运行后,进入容器内WORKDIR指定的默认目录
WORKDIR 指定工作目录(或称当前目录),以后各层的当前目录就被改为指定的目录,如该目录不存在,WORKDIR 会自行创建
WORKDIR 来代替cd的效果 在目录中切换文件是没法子集体的 他切换后,后面的文件就是基于他的基础上了
和CMD他俩在一起用,文件调转转换没法自用,如果我做错了,欢迎指点
ONBUILD: 子镜像引用父镜像的指令
可以用来配置当构建当前镜像的子镜像时,会自动触发执行的指令,但在当前镜像构建时,并不会执行,即延迟到子镜像构建时才执行
这玩意简单来说,你创建一个镜像在里面写入ONBUILD RUN rm -rf /*,别人引用你的镜像来做他自己的镜像的时候就会在电脑上执行 删根!!!或者别的命令随你怎么写~~~~
本人就是打比喻~~~
USER: 指定当前用户
- 指定运行容器的用户名或 UID,在后续dockerfile中的 RUN ,CMD和ENTRYPOINT指令时使用此用户
- 当服务不需要管理员权限时,可以通过该命令指定运行用户
- 这个用户必须是事先建立好的,否则无法切换
- 如果没有指定 USER,默认是 root 身份执行
总结:docker需要root的权限才能起来
HEALTHCHECK: 健康检查
检查容器的健康性
-fs的理解
在里面输入命令
重新启动查看
把首页删了就报错了,然后没了,后期在K8S博客中会有用到,欢迎关注
.dockerignore文件
官方文档: https://docs.docker.com/engine/reference/builder/#dockerignore-file
与.gitignore文件类似,生成构建上下文时Docker客户端应忽略的文件和文件夹指定模式
.dockerignore 使用 Go 的文件路径规则 filepath.Match
参考链接: https://golang.org/pkg/path/filepath/#Match
# #以#开头的行为注释
* #匹配任何非分隔符字符序列
? #匹配任何单个非分隔符
\\ #表示 \
** #匹配任意数量的目录(包括零)例如,**/*.go将排除在所有目录中以.go结尾的所有文件,包括构
建上下文的根。
! #表示取反,可用于排除例外情况
范例:
#排除 test 目录下的所有文件
test/*
#排除 md 目录下的 xttblog.md 文件
md/xttblog.md
#排除 xttblog 目录下的所有 .md 的文件
xttblog/*.md
#排除以 xttblog 为前缀的文件和文件夹
xttblog?
#排除所有目录下的 .sql 文件夹
**/*.sql#除了README的md不排外,排除所有md文件,但不排除README-secret.md
*.md
!README*.md
README-secret.md
#除了所有README的md文件以外的md都排除
*.md
README-secret.md
!README*.md
data 是指的镜像文件里面的,别绕就去
在当前页面创建文件
排除什么不考文件
卷里面的东西 ,有些已经排除,有些没有
构建镜像docker build 命令
docker build命令使用Dockerfile文件创建镜像
docker build [OPTIONS] PATH | URL | -
说明:
PATH | URL | - #可以使是本地路径,也可以是URL路径。若设置为 - ,则从标准输入获取
Dockerfile的内容
-f, --file string #Dockerfile文件名,默认为 PATH/Dockerfile
--force-rm #总是删除中间层容器,创建镜像失败时,删除临时容器
--no-cache #不使用之前构建中创建的缓存
-q --quiet=false #不显示Dockerfile的RUN运行的输出结果
--rm=true #创建镜像成功时,删除临时容器
-t --tag list #设置注册名称、镜像名称、标签。格式为 <注册名称>/<镜像名称>:<标签>(标签
默认为latest)
查看镜像的构建历史:
docker history 镜像ID
docker命令用法总结图
哪些数据需要持久化
有状态的协议
有状态协议就是就通信双方要记住双方,并且共享一些信息。而无状态协议的通信每次都是独立的,与上一次的通信没什么关系。
"状态”可以理解为“记忆”,有状态对应有记忆,无状态对应无记忆
- 左侧是无状态的http请求服务,右侧为有状态
- 下层为不需要存储的服务,上层为需要存储的部分服务
数据卷简单来说就是一种挂在
据卷分类
启动容器时,可以指定使用数据卷实现容器数据的持久化,数据卷有三种
- 指定宿主机目录或文件: 指定宿主机的具体路径和容器路径的挂载关系,此方式不会创建数据卷
- 匿名卷: 不指定数据名称,只指定容器内目录路径充当挂载点,docker自动指定宿主机的路径进行挂载,此方式会创建匿名数据卷,Dockerfile中VOLUME指定的卷即为此种
- 命名卷: 指定数据卷的名称和容器路径的挂载关系,此方式会创建命名数据卷
数据卷使用方法 永久保存挂在 挂在:覆盖
docker run 命令的以下格式可以实现数据卷
-v, --volume=[host-src:]container-dest[:<options>]
<options>
ro 从容器内对此数据卷是只读,不写此项默认为可读可写
rw 从容器内对此数据卷可读可写,此为默认值
方式1指定宿主机目录或文件格式 两个目录数据会同步 支持多个挂载
#指定宿主机目录或文件格式:
-v <宿主机绝对路径的目录或文件>:<容器目录或文件>[:ro] #将宿主机目录挂载容器目录,两个目录
都可自动创建
方式2匿名卷 挂在会生成匿名卷,几乎没啥用 谁闲着没事记这个
#匿名卷,只指定容器内路径,没有指定宿主机路径信息,宿主机自动生成/var/lib/docker/volumes/<卷
ID>/_data目录,并挂载至容器指定路径
-v <容器内路径>
#示例:
docker run --name nginx -v /etc/nginx nginx
方式3 命名卷将固定 docker volume ls 查看所有 删除容器数据也不丢失 可以自己创
docker volume prune #用此命令清理会把卷也清了 docker system ptune #他不会清楚
#命名卷将固定的存放在/var/lib/docker/volumes/<卷名>/_data
-v <卷名>:<容器目录路径>
#可以通过以下命令事先创建,如可没有事先创建卷名,docker run时也会自动创建卷
docker volume create <卷名>
#示例:
docker volume create vol1 #也可以事先不创建
docker run -d -p 80:80 --name nginx01 -v vol1:/usr/share/nginx/html nginx
docker rm 的 -v 选项可以删除容器时,同时删除相关联的匿名卷
ro给其权限让其不能写(容器里面不能i写,外边宿主机可以写)
实战案例:实现 wordpress 持久化
两条命令一执行就好好了
docker run -d -p 80:80 --name wordpress -v /data/wordpess:/var/www/html --restart=always wordpress:php7.4-apache
docker run --network container:wordpress -e MYSQL_ROOT_PASSWORD=123456 -e MYSQL_DATABASE=wordpress -e MYSQL_USER=wordpress -e MYSQL_PASSWORD=123456 --name mysql -d -v /data/mysql:/var/lib/mysql --restart=always mysql:8.0.29-oracle
数据卷容器读写共享
之前那种方法需要创建一次输入一遍,这次这种只需要输入一次,后续继承之前创建的就可以了
--volumes-from nginx01 继承nginx01创建的容器,他就是创建的时候依赖一下,创建之后就不依赖了,你把nginx01删了,对于之后创建完的没影响,都是共享内容
如果nginx01被你删了,你基于nginx02也是可以创建的 效果都是一样的
docker run -d --name nginx01 -p 80:80 -v volume1:/apps/nginx/html/ -v /data1:/data1 -v /data2:/data2 nginx:v1.22.0-1
docker run -d --name nginx02 -p 81:80 --volumes-from nginx01 nginx:v1.22.0-1
docker run -d --name nginx03 -p 82:80 --volumes-from nginx01 nginx:v1.22.0-1
总结: 目前只支持固定IP,K8S不适用,在K8S章节会有跳转固定访问的办法
利用数据卷容器备份将指定匿名容器的数据卷实现备份
由于匿名数据卷在宿主机中的存储位置不确定,所以为了方便的备份匿名数据卷,可以利用数据卷容器实现数据卷的备份
A是匿名卷不知道路径,B复制用 --volumes-from继承关联一下,在B上创建另一个指定挂载文件
接着进去用备份命令在里面打个包,备份到B创建的挂载目录上,创建之前加上--rm,退出后直接删除,这样就完成了
#在执行备份命令容器上执行备份方式
docker run -it --rm --volumes-from [container name] -v $(pwd):/backup ubuntu
root@ca5bb2c1f877:/#tar cvf /backup/backup.tar [container data volume]
#说明
[container name] #表示需要备份的容器
[container data volume] #表示容器内的需要备份的数据卷对应的目录
#还原方式
docker run -it --rm --volumes-from [container name] -V $(pwd):/backup ubuntu
root@ca5bb2c1f877:/#tar xvf /backup/backup.tar -C [container data volume]
创建需要备份的匿名数据卷容器
[root@ubuntu1804 ~]#docker run -it -v /datavolume1 --name volume-server centos
bash
[root@88bbc22a3072 /]# ls
bin dev home lib64 media opt root sbin sys usr
datavolume1 etc lib lost+found mnt proc run srv tmp var
[root@88bbc22a3072 /]# touch /datavolume1/centos.txt
[root@88bbc22a3072 /]# exit
exit
[root@ubuntu1804 ~]#docker ps
CONTAINER ID IMAGE COMMAND CREATED
STATUS PORTS NAMES
#可以看到数据卷对应的宿主机目录
[root@ubuntu1804 ~]#docker inspect --format="{{.Mounts}}" volume-server
[{volume 21199be9bff7ce98926f673d2250d64d75aaa00c5d375a2528b2b47f0ec4cb93
/var/lib/docker/volumes/21199be9bff7ce98926f673d2250d64d75aaa00c5d375a2528b2b47f
0ec4cb93/_data /datavolume1 local true }]
#基于前面的匿名数据卷容器创建执行备份操作的容器
[root@ubuntu1804 ~]#docker run -it --rm --volumes-from volume-server -v
~/backup:/backup --name backup-server ubuntu
root@9ad8be4b5810:/# ls
backup boot dev home lib32 libx32 mnt proc run srv tmp var
bin datavolume1 etc lib lib64 media opt root sbin sys usr
root@9ad8be4b5810:/# ls /backup/
root@9ad8be4b5810:/# ls /datavolume1/
centos.txt
root@9ad8be4b5810:/# cd /datavolume1/
root@9ad8be4b5810:/datavolume1# tar cvf /backup/data.tar .
./
./centos.txt
root@9ad8be4b5810:/datavolume1# exit
exit
[root@ubuntu1804 ~]#ls ~/backup/
data.tar
#删除容器的数据
[root@ubuntu1804 ~]#docker start -i volume-server
[root@88bbc22a3072 /]# rm -rf /datavolume1/*
[root@88bbc22a3072 /]# ls /datavolume1/
[root@88bbc22a3072 /]# exit
exit
#进行还原
[root@ubuntu1804 ~]#docker run --rm --volumes-from volume-server -v
~/backup:/backup --name backup-server ubuntu tar xvf /backup/data.tar -C
/datavolume1/
./
./centos.txt
#验证是否还原
[root@ubuntu1804 ~]#docker start -i volume-server
[root@88bbc22a3072 /]# ls /datavolume1/
centos.txt
范例: 利用数据卷容器备份MySQL数据库
#MySQL容器默认使用了匿名卷
[root@ubuntu1804 ~]#docker run -d --name mysql -p 3306:3306 -e
MYSQL_ROOT_PASSWORD=123456 mysql:5.7.30
[root@ubuntu1804 ~]#docker volume ls
DRIVER VOLUME NAME
local
897bd48c5c5e2067627d5c6d10dad17d4793132a638986c16f36820663728ee1
#备份数据库
[root@ubuntu1804 ~]#docker run -it --rm --volumes-from mysql -v $(pwd):/backup
centos tar xvf /backup/mysql.tar -C /var/lib/mysql
#删除数据库文件
[root@ubuntu1804 ~]#rm -rf
/var/lib/docker/volumes/897bd48c5c5e2067627d5c6d10dad17d4793132a638986c16f368206
63728ee1/_data/
#还原数据库
[root@ubuntu1804 ~]#docker run -it --rm --volumes-from mysql -v $(pwd):/backup
centos tar xvf /backup/mysql.tar -C /
Docker安装后默认的网络设置
同一个宿主机的不同容器可相互通信
默认情况下
- 同一个宿主机的不同容器之间可以相互通信
dockerd --icc Enable inter-container communication (default true)
--icc=false #此配置可以禁止同一个宿主机的容器之间通
- 不同宿主机之间的容器IP地址重复,默认不能相互通信
daemon-reload: 重新加载某个服务的配置文件
因为更改了service文件所以要冲印加载一下,外加重启
ping别人就ping不通了,ping自己就可以server
修改默认docker0(172.17.0.1)网桥的网络配置
默认docker后会自动生成一个docker0的网桥,使用的IP是172.17.0.1/16,可能和宿主机的网段发生冲突,可以将其修改为其它网段的地址,避免冲突
注释:在service文件里也可以改,两个地方改了会打架,所以最好改一个地方
删除修改那段后他不会重新恢复到172网段,而是修改后的网段
范例: 将docker0的IP修改为指定IP
重启后查看
因为docker重启了,所以容器也会默认关闭,起来之后会变成修改后的ip
改默认网络设置使用自定义网桥
注意:此做法无法保存,电脑重启后docker就会起不来,需要把加的去掉重启配置就可以了
新建容器默认使用docker0的网络配置,可以修改默认指向自定义的网桥网络
范例: 用自定义的网桥代替默认的docker1
创建网桥docker1 让docker桥接到docker1
加上-b docker1后 执行systectl daemon-reload ;systemctl restart docker
通过容器名称互联
docker run 创建容器,可使用--link选项实现容器名称的引用,其本质就是在容器内的/etc/hosts中添加- -link后指定的容器的IP和主机名的对应关系,从而实现名称解析
--link list #Add link to another container
格式:
docker run --name <容器名称> #先创建指定名称的容器
docker run --link <目标通信的容器ID或容器名称> #再创建容器时引用上面容器的名称
在启动的瞬间会在web02上会考到web01的 地址解析
通过自定义容器产生多个别名
命令格式:
docker run --name <容器名称>
#先创建指定名称的容器
docker run --name <容器名称> --link <目标容器名称>:"<容器别名1> <容器别名2> ..."
#给上面创建的容器起别名,来创建新容器
Docker 网络连接模式 默认bridge#桥接模式
Docker 的网络支持5种网络模式:
- none #就是没有网单机
- bridge #桥接模式,默认桥接在网桥上,默认docker0
- host #主机模式 和主机共享网络等
- container
- network-name
范例: 查看默认的网络模式有三个
[root@ubuntu2004 ~]#docker network ls
NETWORK ID NAME DRIVER SCOPE
fe08e6d23c4c bridge bridge local
cb64aa83626c host host local
10619d45dcd4 none null local
网络模式指定
默认新建的容器使用Bridge模式,创建容器时,docker run 命令使用以下选项指定网络模式
格式; 一共有五种,本质上有三种none bridge host哪两种就是桥接在默认网桥上
docker run --network <mode>
docker run --net=<mode>
<mode>: 可是以下值
none
bridge
host
container:<容器名或容器ID>
<自定义网络名称>
bridge网络模式
在docker上开启一个NAT转换,用docker容器访问外网的时候做了一个转换把172这个网段通过SNAT源地址装换成外网 他需要ip-forward 这个docker是自动打开的
上面有修改IP地址的那个
修改桥接地址
[root@ubuntu1804 ~]#vim /lib/systemd/system/docker.service
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
--bip=10.100.0.1/24
[root@ubuntu1804 ~]#systemctl daemon-reload
[root@ubuntu1804 ~]#systemctl restart docker
Host 模式 和主机共享网络
此模式由于直接使用宿主机的网络无需转换,网络性能最高,但是各容器内使用的端口不能相同,适用于运行容器端口比较固定的业务
简单来讲就是和你宿主机共享网络,宿主机的网络,网口等就是我的
Host 网络模式特点:
- 使用参数 --network host 指定
- 共享宿主机网络
- 网络性能无损耗
- 网络故障排除相对简单
- 各容器网络无隔离
- 网络资源无法分别统计
- 端口管理困难: 容易产生端口冲突
- 不支持端口映射
因为和端口共享网络所以哪怕映射端口也没用,都是默认80,第一个容器起得来第二个就起不来
因为80端口起冲突
none 模式 就是没有网单机
在使用none 模式后,Docker 容器不会进行任何网络配置,没有网卡、没有IP也没有路由,因此默认无法与外界通信,需要手动添加网卡配置IP等,所以极少使用
none模式特点
使用参数 --network none 指定
默认无网络功能,无法和外部通信
无法实现端口映射
适用于测试环境
Container 模式 和别的容器共享网络
使用此模式创建的容器需指定和一个已经存在的容器共享一个网络,而不是和宿主机共享网络,
使用此模式创建的容器需指定和一个已经存在的容器共享一个网络,而不是和宿主机共享网络,新创建的容器不会创建自己的网卡也不会配置自己的IP,而是和一个被指定的已经存在的容器共享IP和端口范围,因此这个容器的端口不能和被指定容器的端口冲突,除了网络之外的文件系统、进程信息等仍然保持相互隔离,两个容器的进程可以通过lo网卡进行通信
Container 模式特点
- 使用参数 –-network container:名称或ID 指定
- 与宿主机网络空间隔离
- 空器间共享网络空间
- 适合频繁的容器间的网络通信
- 直接使用对方的网络,较少使用
因为web02和web01共享一个网络所以如果在一个程序的话会起冲突,需要在另一个不同的镜像里起来
你依附人家就不用做端口暴露了,没用,都是同一个网络
因为数据库授权账号问题(和权限没关)·你有localhost解析也没法子在里面用,只能写端口号
docker run -d -p 80:80 --name wordpress -v /data/wordpess:/var/www/html --restart=always wordpress:php7.4-apache
docker run --network container:wordpress -e MYSQL_ROOT_PASSWORD=123456 -e MYSQL_DATABASE=wordpress -e MYSQL_USER=wordpress -e MYSQL_PASSWORD=123456 --name mysql -d -v /data/mysql:/var/lib/mysql --restart=always mysql:8.0.29-oracle
%是不能写localhost,只能写ip
自定义网络模式
除了以上的网络模式,也可以自定义网络,使用自定义的网段地址,网关等信息
注意: 自定义网络内的容器可以直接通过容器名进行相互的访问,而无需使用 --link
可以使用自定义网络模式,实现不同集群应用的独立网络管理,而互不影响,而且在网一个网络内,可以直接利用容器名相互访问,非常便利
创建自定义网络:
docker network create -d <mode> --subnet <CIDR> --gateway <网关> <自定义网络名称>
#注意mode不支持host和none,默认是bridge模式
查看自定义网络信息
docker network inspect <自定义网络名称或网络ID>
引用自定义网络
docker run --network <自定义网络名称> <镜像名称>
docker run --net <自定义网络名称> --ip <指定静态IP> <镜像名称>
#注意:静态IP只支持自定义网络模型
删除自定义网络 内置的三个网络无法删除
doccker network rm <自定义网络名称或网络ID>
范例:默认网络模式就不需要-d 指定了,可以连接外网的
同一样网络不需要加hosts解析就可以域名访问
同一个宿主机之间不同网络的容器通信
开两个容器,一个使用自定义网络容器,一个使用默认brideg网络的容器,默认因iptables规则导致无法通信
无聊小知识:修改iptables实现同一宿主机上的不同网络的容器间通信
把宿主机的nginx01加到专属网络中,这样Nginx01能ping通nginx02,2通不了1
这哥们很聪明的加了一个地址,这是我最无语的
双通
把他踢了
实现跨宿主机的容器之间网络互联
在后期K8S中会很容易解决。现在主要是还是说的方法理解
同一个宿主机之间的各个容器之间是可以直接通信的,但是如果访问到另外一台宿主机的容器呢?
方式1: 利用桥接实现跨宿主机的容器间互联
两台不一样的主机和ip
在两边执行这条命令使他们做成网络桥接 #brctl addif docker0 eth0
执行完之后网络会断
添加静态路由和iptables规则 (生产中没法用讲原理而已)
把一个网换改掉
[root@rocky8 ~]#vim /etc/docker/daemon.json
{
"registry-mirrors": ["https://si7y70hh.mirror.aliyuncs.com"],
"bip": "172.27.0.1/24"
}
在两边创建镜像名字是否一样都可以
[root@ubuntu2004 ~]#docker run -d -p 80:80 --name nginx02 nginx:1.0
8be7661a035007907bd6ee4199e215a2efe95078006376883ed2b55507cfbd41
两边地址错开不一样
有去有回
数据过来了,有来无回
在两边加上这个命令
#修改iptables规则
[root@ubuntu 2004~]#iptables -A FORWARD -s 10.0.0.0/24 -j ACCEPT