Docker 进阶
可视化
- portainer
什么是 portainer
Docker 图形化界面管理工具!提供一个后台面板供我们使用!
[root@localhost ~]# docker run -d -p 8000:9000 --restart=always -v /var/run/docker/sock:/var/run/docker.sock --privileged=true portainer/portainer
访问测试:http://ip:8000
Docker 镜像讲解
镜像是什么
镜像是一种轻量级、可执行的独立软件包,用来打包软件运行环境和基于运行环境开发的软件,它包含运行某个软件所需的所有内容,包括代码、运行时、库、环境变量和配置文件。
所有的应用,直接打包 docker 镜像,就可以直接跑起来!
如何得到镜像:
- 从远程仓库下载
- 朋友拷贝给你
- 自己制作一个镜像 Dockerfile
Docker 镜像加载原理
UnionFS (联合文件系统)
UnionFS(联合文件系统):Union 文件系统是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下。Union 文件系统是 Docker 镜像的基础。镜像可以通过分层来继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。
特性:一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录。
commit 镜像
docker commit 提交容器成为一个新的副本
# 命令和git原理类似
docker commit -m="描述信息" -a="作者" 容器 id 目标镜像名:[TAG]
实际测试:
# 启动一个默认的 tomcat
# 发现这个默认的 tomcat 是没有 webapps 应用,镜像的原因,官方的镜像默认 webapps 下面没有文件
# 我自己拷贝进去了基本的文件
# 将我们操作过的容器通过 commit 提交为一个镜像!
容器数据卷
什么是容器数据卷
docker 的理念
将应用和环境打包成一个镜像
数据?如果数据都在容器中,那么我们容器删除,数据就会丢失~需求:数据可以持久化
容器之间可以有一个数据共享的技术!Docker 容器产生的数据,同步到本地
这就是卷技术 目录的挂在 将容器内的目录 挂载在 Linux 上
使用数据卷
方式一:直接使用命令来挂载 -v
docker run -it -v 主机目录:容器内目录
# 测试
docker run -it -v /home/test:/home centos /bin/bash
# 启动起来的时候我们可以通过 docker inspect 容器 id
测试文件的同步
好处:我们以后修改只需要在本地修改即可,容器内会自动同步
实战:安装 MySQL
思考: MySQL 的数据持久化问题!
# 获取镜像
docker pull mysql:5.7
# 运行容器,需要做数据挂载!
# 安装 Mysql ,需要配置密码
# 官方测试:docker run --name some-mysql -e MYSQL_ROOT_PASSWORD=password -d
mysql:tag
# 启动mysql
- d 后台运行
- p 端口映射
- v 卷挂载
- e 环境配置
-- name 容器名字
docker run -d -p 3306:3306 -v /home/mysql/conf:/etc/mysql/conf.d -v /home/mysql/data:/var/lib/mysl -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql:5.7
具名挂载和匿名挂载
# 匿名挂载
-v 容器内的路径
docker run -d -P --name nginx01 -v /etc/nginx nginx
# 查看所有 volume 的情况
docker volume ls
# 查看所有的 volume 的情况
# 这里发现,这种就是匿名挂载,我们在 -v 只写了容器内的路径,没有写容器外的路径
# 具名挂载
docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx nginx
# 通过 -v 卷名:容器内路径
# 查看一下这个卷
所有的 docker 容器内的卷,没有指定目录的情况下都在 /var/lib/docker/volumes/xxx/_data
我们通过具名挂载可以方便的找到我们的一个卷,大多数情况都使用 具名挂载
# 如何确定是具名挂载还是匿名挂载,还是指定路径挂载
-v 容器内路径 # 匿名挂载
-v 卷名:容器内路径 # 具名挂载
-v /容器外地址:容器内地址 # 指定路径挂载
拓展:
# ro: read-only rw:read-write
docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx:ro nginx
docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx:ro nginx
初识 Dockerfile
Dockerfile 就是用来构建 docker 镜像的构建文件! 通过这个脚步可以生成镜像,镜像是一层一层的,脚步一个个的命令,每个命令都是一层!
# 创建一个 dockerfile 文件,名字可以随机 建议 Dockerfile
# 文件中的内容 指令(大写) 参数
FROM centos:7
VOLUME ["volume01", "volume02"]
CMD echo "-----end-----"
CMD /bin/bash
数据卷容器
多个 mysql 容器
# 启动3个容器,通过我们刚才自己写的镜像启动
多个mysql实现数据共享
docker run -d -p 3306:3306 -v /etc/mysql/conf.d -v /var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql:5.7
docker run -d -p 3307:3306 -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 --volume-from mysql01 mysql:5.7
# 这个时候,可以实现两个容器数据同步
结论:
容器之间配置信息的传递,数据卷容器的生命周期一直持续到没有容器为止
但是一旦你持久化到了本地,这个时候,本地的数据是不会删除的。
Dockerfile
Dockerfile 是用来构建 docker 镜像的文件,命令参数脚本!
构建步骤:
- 编写一个 Dockerfile 文件
- docker build 构建成为一个镜像
- docker run 运行镜像
- docker push 发布镜像
很多官方镜像都是基础包,很多功能都没有,所有我们通常会自己搭建自己的镜像
Dockerfile 的构建过程
基础知识:\
- 每个保留关键字都是必须是大写字母
- 执行从上到下顺序执行
- #表示注释
- 每一个指令都会创建提交一个新的镜像层,并提交!
Dockerfile 的指令
FROM # 基础镜像,一切从这里开始
MAINTAINER # 镜像是谁写的 姓名+邮箱
RUN # 镜像构建的时候需要运行的命令
ADD # 步骤:tomcat 镜像,这个tomcat压缩包!添加内容
WORKDIE # 镜像的工作目录
VOLUME # 挂载目录
EXPOSE # 指定对外的端口
CMD # 指定这个容器启动的时候要运行的命令
ENTRYPOINT # 指定这个容器启动的时候要运行的命令,可以追加命令
ONBUILD # 当构建一个被继承 Dockerfile 这个时候就会运行 ONBUILD 指令 触发指令
COPY # 类是 ADD 将文件拷贝到镜像中
ENV # 构建的时候设置环境变量
实战测试
Docker Hub 中99% 镜像都是从这个基础镜像过来的 FROM scratch 然后配置软件和配置
创建一个自己的 centos
# 编写 Dockerfile 的文件
FROM centos:7
ENV MYPATH /usr/local
WORKDIR $MYPATH
RUN yum -y install vim
RUn yum -y install net-tool
EXPOSE 80
CMD echo $MYPATH
CMD /bin/bash
# 通过这个文件构建镜像
docker build -f dockerfile文件路径 -t 镜像名:[TAG]
# 测试运行
我们可以列出本地进行的变更历史
我们平时拿到一个镜像,可以研究一下,它是怎么做的?
CMD 和 ENTRYPOINT 区别
CMD # 指定这个容器启动的时候要运行的命令
ENTRYPOINT # 指定这个容器启动的时候要运行的命令,可以追加命令
测试cmd
# 编写 dockerfile 文件
vim dockerfile-cmd-test
FROM centos:7
CMD ["ls", "-a"]
# 构建镜像
docker build -f dockerfile-cmd-test -t cmdtest .
# run 运行 发现我们的 ls -a 命令生效
# 想追加一个命令 -l ls -al 就会异常
测试 entrypoint
Dockerfile 中很多命令都十分相似,我们需要了解他们的区别,我们最好的学习就是对比他们 然后测试效果
实战:Tomcat 镜像
- 准备镜像文件 tomcat 压缩包,jdk 的压缩包
- 编写 dockerfile 文件 官方命名
Dockerfile, build 会自动寻找这个文件,就不需要 -f 指定了
FROM centos:7
MAINTAINER duke<401007124@qq.com>
COPY readme.txt /usr/local/readme.txt
ADD apache-tomcat-9.0.24.tar.gz /usr/local/
ADD jdk-18_linux-x64_bin.tar.gz /usr/local/
RUN yum -y install vim
ENV MYPATH /usr/local
WORKDIR $MYPATH
ENV JAVA_HOME /usr/local/jdk-18.0.2
ENV CLASSPATH $/JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.24
ENV CATALINA_BASH /usr/local/apache-tomcat-9.0.24
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/bin:$CATALINA_BASH/bin
EXPOSE 8080
CMD /usr/local/apache-tomcat-9.0.24/bin/startup.sh && tail -F /usr/local/apache-tomcat-9.0.24/bin/logs/catalina.out
- 构建镜像
# docker build -t diytomcat .
- 运行镜像
# docker run -d -p 8080:8080 --name mytomcat -v /home/duke/build/tomcat/test:/usr/local/apache-tomcat-9.0.24/webapps/test diytomcat
- 访问测试
- 发布项目(由于做了卷挂载,我们可以直接在本地编写项目就可以了)
发布自己的镜像
DockerHub
- 地址 hub.docker.com/ 注册账号
- 在我们的服务器上提交的镜像
[root@localhost ceshi]# docker login --help
Usage: docker login [OPTIONS] [SERVER]
Log in to a Docker registry.
If no server is specified, the default is defined by the daemon.
Options:
-p, --password string Password
--password-stdin Take the password from stdin
-u, --username string Username
- 登录完毕后就可以提交镜像了,就是docker push
# push 到自己的DockerHub
1. docker tag 镜像id DockerHub名称/镜像名称:[TAG]
2. docker push DockerHub名称/镜像名称:[TAG]
Docker 网络
理解网络 Docker 0
清空所有环境
测试
三个网络
# 问题:docker 是如何处理容器网络访问的?
[root@localhost ~]# docker run -d -P --name tomcat01 tomcat
# 查看容器的内部网络地址:ip addr
root@7397f3a0e066:/usr/local/tomcat# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
7: eth0@if8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
# 思考: Linux 能不能 ping 通 容器内部
[root@localhost ~]# ping 192.168.0.1
PING 192.168.0.1 (192.168.0.1) 56(84) bytes of data.
64 bytes from 192.168.0.1: icmp_seq=1 ttl=64 time=0.036 ms
64 bytes from 192.168.0.1: icmp_seq=2 ttl=64 time=0.037 ms
# Linux 可以 ping 通 docker 容器内部
原理
- 我们每启动cker 容器 docker 就会给docker 容器分配一个 ip ,我们只需要安装了 docker, 就会有一个网卡 docker0 桥接模式,使用的技术是 evth-pair 技术!
再次测试 ip addr
# 我们发现这个容器带来网卡,都是一对一对的
# evth-pair 就是一对的虚拟设备接口,他们都是成对出现的,一端连着协议,一端彼此相连
# 正因为有这个特性,evth-pair 充当一个桥梁,连接各种虚拟网络设备的
- 容器之间是否可以 ping 通
# 容器与容器之间是可以通信的
结论:容器间 是公用的一个路由器,docker0
所有的容器不指定网络的情况下,都是 docker0 路由的,docker会给我们的容器分配一个默认的可用 IP
小结
Docker 使用的是 Linux 的桥接,宿主机中的一个 docker 容器的网桥 docker0
Docker 中的所有的网络接口都是虚拟的。虚拟的转发效率高
只要容器删除,对应的网桥一对就没了
--link
思考一个场景,我们编写了一个微服务,database url=ip:端口 项目不重启,数据库 ip 换掉了 处理这个问题 可以通过,名字来进行访问容器
# 肯定 ping 不通
docker exec -it tomcat01 ping tomcat02
# 如何可以解决的呢
# 通过 --link 可以解决
docker run -d -P --name tomcat03 --link tomcat02 tomcat
# 反向的连接可以 ping 通吗
# 不能 ping 通
探究: inspect
其实这个 tomcat03 就是在本地配置了 tomcat02 的配置
不建议使用 --link 建议使用自定义网络
自定义网络
查看所有的 docker 网络
[root@localhost ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
26ef6da5836c bridge bridge local
b56f6f7f8438 duek-net bridge local
9f681857697a host host local
aee49b42fca9 none null local
网络模式
brige : 桥接 docker
none :不配置网络
host : 和宿主机共享网络
container : 容器网络连通
测试
# 我们可以直接启动命令 --net bridge,而这个就是我们的 docker0
docker run -d -P --name tomcat01 tomcat
docker run -d -P --name tomcat01 --net bridge tomcat
# docker0 特点:默认,域名不能访问,--link 可以打通连接
# 我们自定义网络
docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
网络连通
Usage: docker network connect [OPTIONS] NETWORK CONTAINER
Connect a container to a network
Options:
--alias strings Add network-scoped alias for the container
--driver-opt strings driver options for the network
--ip string IPv4 address (e.g., 172.30.100.104)
--ip6 string IPv6 address (e.g., 2001:db8::33)
--link list Add link to another container
--link-local-ip strings Add a link-local address for the container
# 测试打通两个不同网段
docker network connect mynet tomcat01
# 连通之后就是将 tomcat01 放到了 mynet 网络下
# 一个容器两个 ip