Docker 进阶

87 阅读11分钟

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 提交为一个镜像!

image.png

容器数据卷

什么是容器数据卷

docker 的理念 将应用和环境打包成一个镜像
数据?如果数据都在容器中,那么我们容器删除,数据就会丢失~需求:数据可以持久化
容器之间可以有一个数据共享的技术!Docker 容器产生的数据,同步到本地
这就是卷技术 目录的挂在 将容器内的目录 挂载在 Linux 上

image.png

使用数据卷

方式一:直接使用命令来挂载 -v

docker run -it -v 主机目录:容器内目录

# 测试
docker run -it -v /home/test:/home centos /bin/bash

# 启动起来的时候我们可以通过 docker inspect 容器 id

image.png

测试文件的同步

image.png

好处:我们以后修改只需要在本地修改即可,容器内会自动同步

实战:安装 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 卷名:容器内路径
# 查看一下这个卷

image.png

image.png

所有的 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 容器

image.png

# 启动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 的构建过程

基础知识:\

  1. 每个保留关键字都是必须是大写字母
  2. 执行从上到下顺序执行
  3. #表示注释
  4. 每一个指令都会创建提交一个新的镜像层,并提交!

image.png

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]

# 测试运行

我们可以列出本地进行的变更历史

image.png

我们平时拿到一个镜像,可以研究一下,它是怎么做的?

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

image.png

Dockerfile 中很多命令都十分相似,我们需要了解他们的区别,我们最好的学习就是对比他们 然后测试效果

实战:Tomcat 镜像

  1. 准备镜像文件 tomcat 压缩包,jdk 的压缩包
  2. 编写 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
  1. 构建镜像
# docker build -t diytomcat .
  1. 运行镜像
# docker run -d -p 8080:8080 --name mytomcat -v /home/duke/build/tomcat/test:/usr/local/apache-tomcat-9.0.24/webapps/test diytomcat
  1. 访问测试
  2. 发布项目(由于做了卷挂载,我们可以直接在本地编写项目就可以了)

发布自己的镜像

DockerHub

  1. 地址 hub.docker.com/ 注册账号
  2. 在我们的服务器上提交的镜像
[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
  1. 登录完毕后就可以提交镜像了,就是docker push
# push 到自己的DockerHub
1. docker tag 镜像id DockerHub名称/镜像名称:[TAG]
2. docker push DockerHub名称/镜像名称:[TAG]

Docker 网络

理解网络 Docker 0

清空所有环境

测试

image.png

三个网络

# 问题:docker 是如何处理容器网络访问的?

image.png

[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 容器内部

原理

  1. 我们每启动cker 容器 docker 就会给docker 容器分配一个 ip ,我们只需要安装了 docker, 就会有一个网卡 docker0 桥接模式,使用的技术是 evth-pair 技术!

再次测试 ip addr

# 我们发现这个容器带来网卡,都是一对一对的
# evth-pair 就是一对的虚拟设备接口,他们都是成对出现的,一端连着协议,一端彼此相连
# 正因为有这个特性,evth-pair 充当一个桥梁,连接各种虚拟网络设备的

  1. 容器之间是否可以 ping 通
# 容器与容器之间是可以通信的

image.png

结论:容器间 是公用的一个路由器,docker0
所有的容器不指定网络的情况下,都是 docker0 路由的,docker会给我们的容器分配一个默认的可用 IP

小结

Docker 使用的是 Linux 的桥接,宿主机中的一个 docker 容器的网桥 docker0

image.png

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

image.png

其实这个 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