分类 Docker 下的文章

简介

之前使用Docker 都是手动去操作单个容器 比如: 编写DockerFile 手动执行 build run 等操作, 这样的弊端是如果我们有很多服务的话一个一个的执行会很麻烦
所以使用Docker Compose来轻松高效的管理容器, 可以定义运行多个容器.

Docker Compose 特性

  • 定义, 运行多个容器.
  • YAML file 配置文件.
  • docker-compose 命令.

自己理解

compose是docker官方开源的项目, 需要安装.
比如有一个 web服务 我们需要安装 nginx, php, mysql, redis 多个容器,我们使用DockerFile一个一个的去写, 一个一个的去运行命令会非常的麻烦.

安装 docker-compose

  • 官方提供的GitHub地址太慢,这里使用国内的镜像: 地址
  • 安装完成使用命令 docker-compose version 有版本信息表示安装成功

快速上手

  1. 创建应用 app.py
  2. Dockerfile 应用打包成镜像
  3. docker-compose yaml文件 定义整个服务(所需的环境)
  4. 启动compose项目

流程

  1. 创建网络
  2. 执行 docker-composer yaml
  3. 启动服务

docker-compose 配置编写规则

yaml 规则

#  yaml 有三层

version '' # 1.版本 对应docker版本
service '' # 2.服务
    服务1 : web
        # 服务配置
        image
        build
        network
    服务2 : redis
    .....

# 3.其他配置 网络/卷/全局规则
volumes:
networks:
configs:    

理解Docker0网卡

29684-tr2gsst6iqp.png

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

  • 我们通过命令查看某一个容器的内部ip 可以看出容器内部的ip和docker0网卡是在同一网段的
  • 并且宿主机和容器之间是可以相互ping通的
docker exec -it tomcat1 ip addr

77598-5q4381v46rc.png

原理

  • 每启动一个容器, docker就会给容器分配一个ip. 只要安装了docker 就会有一个docker0的网卡
  • docker0的网卡和真实的物理网卡之间是桥接模式
  • 使用的技术是 evth-pair技术

evth-pair 技术

  • 当我们启动容器的时候就会生成一对网卡
  • evth-pair 就是一对虚拟设备接口, 他们都是成对出现的 一段连着协议, 一段彼此相连
  • 有了这种特性 evth-pair 充当一个桥梁,连接各种虚拟设备

24034-yds8lzhwgkq.png
06812-rqz8sfmlcps.png

画图理解

75492-to9cuhy2v9.png

结论

  • tomcat01 和 tomcat02 是公用一个路由器 docker0
  • 容器在不指定网络的情况下, 都是走docker0 路由的 docker会给容器分配一个默认的ip
  • Docker中所有的网络接口都是虚拟的
    93211-0tos63kx77z.png

容器互联 --link

  • 通过上面我们会发现容器之间可以通过ip地址是可以ping通的
  • 那么再某些情况下不用ip 我们可不可以用容器名的方式 ping通?
  • 可以使用 --link 来解决上面的问题
# 我们重新启动一个tomcat 并且 --link tomcat1
docker run -d -P --link tomcat tomcat

# 完成之后我们就可以ping通了
docker exec -it jovial_chebyshev ping tomcat1

PING tomcat1 (172.17.0.4) 56(84) bytes of data.
64 bytes from tomcat1 (172.17.0.4): icmp_seq=1 ttl=64 time=0.069 ms
64 bytes from tomcat1 (172.17.0.4): icmp_seq=2 ttl=64 time=0.060 ms
64 bytes from tomcat1 (172.17.0.4): icmp_seq=4 ttl=64 time=0.069 ms
--- tomcat1 ping statistics ---
  • 这样做有一个弊端就是 反向 ping 是不通的
  • 原理就是在 jovial_chebyshev 容器中的 /etc/host 中有写
docker exec -it jovial_chebyshev cat /etc/hosts
127.0.0.1    localhost
::1    localhost ip6-localhost ip6-loopback
fe00::0    ip6-localnet
ff00::0    ip6-mcastprefix
ff02::1    ip6-allnodes
ff02::2    ip6-allrouters
172.17.0.4    tomcat1 612aeb07e2e7
172.17.0.2    e7613df5b961
  • --link 就是在我们 hosts 中增加了一条虚拟域名

自定义网络

查看所有的docker网络

docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
ea834618e218        bridge              bridge              local
2da75ecdb782        host                host                local
d7c3fa26b1bd        none                null                local

网络模式

  • bridge : 桥接模式(docker默认)
  • none : 不配置网络
  • host : 和宿主机共享网络
  • container : 容器网络连通(用的少, 局限很大)

创建自定义网络

  • --subnet 子网
  • --gateway 网关
  • --driver 默认桥接模式 不写也可以
docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet

查看自己创建的网络

  • 命令: docker network inspect mynet
[
    {
        "Name": "mynet",
        "Id": "6eb44c49b01928fd5c010c72c2738980814855e372a215eac422d35bdb1c70c4",
        "Created": "2020-09-22T05:58:08.319032125Z",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "192.168.0.0/16",
                    "Gateway": "192.168.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {},
        "Options": {},
        "Labels": {}
    }
]

使用自己创建的网络

  • --net
docker run -d -P --net mynet --name tomcat-net-01 tomcat
再次测试
  • 使用自己的网络创建两个容器并且相互ping 都是可以ping通的
  • 比之前的 --link 要好很多
docker exec -it tomcat-net-01 ping tomcat-net-02
PING tomcat-net-02 (192.168.0.3) 56(84) bytes of data.
64 bytes from tomcat-net-02.mynet (192.168.0.3): icmp_seq=1 ttl=64 time=0.073 ms
64 bytes from tomcat-net-02.mynet (192.168.0.3): icmp_seq=2 ttl=64 time=0.063 ms
64 bytes from tomcat-net-02.mynet (192.168.0.3): icmp_seq=3 ttl=64 time=0.063 ms

#反向ping 也是可以的
PING tomcat-net-01 (192.168.0.2) 56(84) bytes of data.
64 bytes from tomcat-net-01.mynet (192.168.0.2): icmp_seq=1 ttl=64 time=0.100 ms
64 bytes from tomcat-net-01.mynet (192.168.0.2): icmp_seq=2 ttl=64 time=0.078 ms

网络连通

容器在不同的网段内如何实现互通?

示意图

13263-x84wd8oss4.png

  • 我们会发现不同网段的容器不能ping通的.
docker exec -it tomcat01 ping tomcat-net-01
ping: tomcat-net-01: Name or service not known
  • 所以需要使用 --network connect 命令

连通

docker network connect mynet tomcat01

查看

docker network inspect mynet

[
    {
        "Name": "mynet",
        .....
        .....
        ...
        "Containers": {
            "0796e3b7250d5c49372183e28266de528dfe072bb884220aeff9f0ccab4521a7": {
                "Name": "tomcat-net-01",
                "EndpointID": "e53cde49134bf3fb72f9bcd801ac73e208705b8cae416b689a726511b1125d49",
                "MacAddress": "02:42:c0:a8:00:02",
                "IPv4Address": "192.168.0.2/16",
                "IPv6Address": ""
            },
            "2a187f1b05a15d33c5cc382c2b84d0b93fa4748f3e2ce4daed0ca0bc7a4d0500": {
                "Name": "tomcat01",
                "EndpointID": "652193a8312425944682a4b48f2f1a1d35ec5e4cea6806fbe0d5be11380627e8",
                "MacAddress": "02:42:c0:a8:00:04",
                "IPv4Address": "192.168.0.4/16",
                "IPv6Address": ""
            },
           .....
        },
        "Options": {},
        "Labels": {}
    }
]
  • 连通之后我们可以看到 tomcat01 容器直接放到了 mynet的网络下
  • 这就是一个容器两个ip地址
  • 这样我们就可以ping通了
docker exec -it tomcat01 ping tomcat-net-01

PING tomcat-net-01 (192.168.0.2) 56(84) bytes of data.
64 bytes from tomcat-net-01.mynet (192.168.0.2): icmp_seq=1 ttl=64 time=0.082 ms
64 bytes from tomcat-net-01.mynet (192.168.0.2): icmp_seq=2 ttl=64 time=0.074 ms

DockerFile 介绍

  • dockerfile 是用来构建docker镜像的文件, 命令参数脚本.

DockerFile 构建过程

基础知识

  • 每个保留关键字(指令) 都必须是大写字母
  • 从上到下的执行顺序
  • 每一个指令都会创建提交一个新的镜像层, 并提交

DockerFile 指令

FROM        # 基础镜像, 所有的东西都从这里开始
MAINTAINER  # 镜像作者 姓名+邮箱
RUN         # 镜像构建的时候需要运行的命令 
ADD         # 需要加入的内容 比如 mysql, nginx, Ubuntu 等
WORKDIR     # 镜像的工作目录
VOLUME      # 挂载目录
EXPOSE      # 暴露端口配置
CMD         # 指定这个容器启动的时候要运行的命令, 只有最后一个会生效, 可被替代
ENTRYPOINT  # 指定这个容器启动的时候要运行的命令, 可以追加命令
ONBUILD     # 当构建一个被继承 DockerFile 这个时候需要这个命令
COPY        # 将我们的文件拷贝到镜像中
ENV         # 构建的时候设置环境变量

使用 DockerFile 构建 dnmp

todo ....

发布镜像到 DockerHub

前提条件

  1. 注册docker账号
  2. 在终端登录上自己的账号 命令: docker login

发布命令

docker push 作者名字/镜像名字:标签名字

什么是容器数据卷

  • docker的理念, 将应用和环境打包成一个镜像, 如果应用产生数据, 那么我们删除容器数据就会丢失.
  • 所以我们需要数据可以持久化, 比如 mysql的数据可以存储在本地! 并且容器之间可以数据共享, 这就是数据卷技术.

使用数据卷挂载目录

# 命令中 -v 就是在挂载目录 主机目录:容器内目录
docker run -it -v /home/test:/home centos /bin/bash

可以使用 docker inspect 命令 查看挂载

50425-oaf25b0xjpe.png

mysql容器实战

# 命令详解
# -d 后台运行
# -p 端口映射 宿主机端口:容器内端口
# -v 数据卷挂载
# -e 环境配置
# --name 容器名字

docker run -d -p 3333:3306 -v /home/docker/mysql/conf:/etc/mysql/conf.d -v /home/docker/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=root --name my-mysql mysql

假设我们将容器删除, 就会发现挂载到本地的数据劵依旧没有丢失, 这就实现了容器数据化持久功能

具名挂载和匿名挂载

docker的挂载方式有三种 具名挂载和匿名挂载 指定路径挂载, 上面mysql实战中就使用了指定路径挂载

匿名挂载

# -v 直接写容器内路径

docker run -d -P --name nginx01 -v /etc/nginx nginx

# 启动容器后, 可以使用 docker volume ls 命令来查看所有卷
docker volume ls
DRIVER              VOLUME NAME
local               44bf15e29c95e85ab32f4d94c7e2766d0880d602342cf1ac00e3044c1c3415f8
local               723cc8cf114d9d4bb4ca51092b11fccf2b29d0927739414938a2cde22de4e43e

具名挂载

# -v 卷名:容器内路径
docker run -d -P --name nginx02 -v juming:/etc/nginx nginx

# 再次查看所有的卷
docker volume ls
DRIVER              VOLUME NAME
local               44bf15e29c95e85ab32f4d94c7e2766d0880d602342cf1ac00e3044c1c3415f8
local               723cc8cf114d9d4bb4ca51092b11fccf2b29d0927739414938a2cde22de4e43e
local               juming

查看匿名和具名挂载的目录

# 使用 docker volume inspect 卷名来查看挂载的目录

docker volume  inspect 44bf15e29c95e85ab32f4d94c7e2766d0880d602342cf1ac00e3044c1c3415f8

[
    {
        "CreatedAt": "2020-09-11T05:49:44Z",
        "Driver": "local",
        "Labels": null,
        "Mountpoint": "/var/lib/docker/volumes/44bf15e29c95e85ab32f4d94c7e2766d0880d602342cf1ac00e3044c1c3415f8/_data",
        "Name": "44bf15e29c95e85ab32f4d94c7e2766d0880d602342cf1ac00e3044c1c3415f8",
        "Options": null,
        "Scope": "local"
    }
]
  • /var/lib/docker/ 目录就是docker的工作目录
  • 在其中 /var/lib/docker/volumes/ 目录就是存放了 docker 的所有挂载卷
  • 进入到目录中就可以看到挂载的目录了
    43432-ghe8velcfed.png

总结

-v 容器内路径            # 匿名挂载
-v 卷名:容器内路径        # 具名挂载
-v 宿主机路径:容器内路径   # 指定路径挂载