Docker | DaoCloud Reference:

https://docs.docker.com

https://get.daocloud.io/#install-docker

1 Docker 安装

1.1 在Mac系统中安装 Docker

DaoCloud Reference:https://get.daocloud.io/#install-docker-for-mac-windows

Docker Reference:https://www.docker.com/products/docker#/mac

:::color2

在Mac上运行Docker。系统要求,OS X 10.10.3 或者更高版本,至少4G内存,4.3.30版本以前的VirtualBox会与Docker for Mac产生冲突,所以请卸载旧版本的VitrualBox。

:::

1.2 在Windows系统中安装 Docker

DaoCloud Reference:https://get.daocloud.io/#install-docker-for-mac-windows

Docker Reference:https://www.docker.com/products/docker#/windows

:::color2

在Windows安装Linux的Application,必然需要Windows有一些条件,并且条件对于Windows来讲更加的苛刻。 在Windows上运行Docker。系统要求,Windows10 x64位,支持Hyper-V。[ Hyper-V 是微软的一种实现虚拟化的一个技术 ] 如果您的电脑版本过旧,可以使用 Docker Toolbox 在Windows或者Mac上运行Docker。适用于Mac OS X 10.8+ 或者 Windows 7/8.1。

:::

系统要求:

  • Windows 10 以上的操作系统版本
  • 必须启用Hyper-V和Containers Windows功能。
  • 要在Windows 10上成功运行Client Hyper-V,需要满足以下硬件先决条件:
    • 具有二级地址转换(SLAT)的 64位处理器
    • 4GB系统内存
    • 必须在BIOS设置中启用BIOS级硬件虚拟化支持。有关更多信息,请参见虚拟化

:::color2

  1. 虚拟化功能启用

:::

💫31 Docker Base - 图1

:::color2

  1. Hyper-V 功能启用

:::

💫31 Docker Base - 图2

1.3 Vagrant

GitHub Reference:https://github.com/hashicorp/vagrant

Vagrant Reference:https://www.vagrantup.com/

Reference:

https://www.cnblogs.com/yehuisir/p/13334602.html

1.3.1 Vagrant 简介

💫31 Docker Base - 图3

Vagrant 是一款用来构建虚拟开发环境的工具,非常适合 php/python/ruby/java 这类语言开发 web 应用,“代码在我机子上运行没有问题”这种说辞将成为历史。 我们可以通过 Vagrant 封装一个 Linux 的开发环境,分发给团队成员。成员可以在自己喜欢的桌面系统(Mac/Windows/Linux)上开发程序,代码却能统一在封装好的环境里运行,非常霸气。 当然啦,如果你和我一样有系统洁癖的话,也非常推荐使用 Vagrant 。毕竟电脑上经常莫名其妙会安装各种环境,导致有时候开发项目并不清楚究竟项目的依赖环境具体有哪些,使用 Vagrant 是一个很有逼格的解决方案。我自己的 Surface 和 Mac 都搭建了各种 Vagrant 的虚拟环境——有专门运行 Hexo 博客的,有专门运行 Wordpress 的,也有专门用来学习 Linux 的…… 当然如果你用各种虚拟机如 VirtualBox、VMware、AWS、Parallels Desktop 来搭建虚拟开发环境也没有什么不可以。但是我这里还是安利一下 Vagrant 。用 Vagrant 来装,不仅安装起来更方便快捷,而且后面真正开发中也会有很多好处。

1.3.2 Vargent 的优点

1、 统一开发环境。一次配置打包,统一分发给团队成员,统一团队开发环境,解决诸如“编码问题”,“缺少模块”,“配置文件不同”带来的问题; 2、 避免重复搭建开发环境。新员工加入,不用浪费时间搭建开发环境,快速加入开发,减少时间成本的浪费; 3、 多个相互隔离开发环境。可以在不用box里跑不同的语言,或者编译安装同一语言不同版本,搭建多个相互隔离的开发环境,卸载清除时也很快捷轻松。

1.3.3 安装 Vargent

1.3.3.1 安装 VirtualBox

VirtualBox 是一个免费开源的虚拟机,相对 VMware 来说更加小巧,个人比较喜欢。

:::color2

下载地址:https://www.virtualbox.org/wiki/Downloads ::: 虽然 Vagrant 也支持 VMware,不过 VMware 是收费的,对应的 Vagrant 版本也是收费的。

1.3.3.2 安装 Vagrant

:::color2

下载地址:http://downloads.vagrantup.com ::: 有 Windows 版,也有 Mac 版,找到适合自己的包来安装就好了,和安装别的软件没啥区别,我这里就不演示了,双击来安装,到终端中执行:
  1. # 查看 vagrant 的版本号
  2. vagrant -v
  3. # 查看 vagrant 的帮助用法
  4. vagrant --help
如果看到输出,表示已经装好了。

💫31 Docker Base - 图4

1.3.3.3 到 vagrantcloud 上找一个 box 镜像并添加

:::color2 如果你要其他系统的镜像,可以来这里下载:http://www.vagrantbox.es

:::

可以看到这里有上百种不同的镜像,而且全部都可以通过命令行一键安装。(但是国内的网络会经常失败。) 所以也可以下载之后再安装。

1.3.3.4 Vagrant & VirtualBox for Mac

Video Reference:Vagrant & VirtualBox for Mac

1.3.3.5 Vagrant & VirtualBox for Windows

:::color2 推荐版本是<font style="color:rgb(77, 77, 77);">VirtualBox-6.0.24-139119-Win</font><font style="color:rgb(77, 77, 77);">Vagrant_2.2.16</font>

:::

Video Reference:Vagrant & VirtualBox for Windows

Document Reference:https://blog.csdn.net/qq_44713454/article/details/119943743

  1. # 在某个盘中创建相应的目录
  2. E:\> mkdir centos7
  3. # 进入到相应的目录
  4. E:\> cd centos7
  5. # vagrant初始化
  6. E:\centos7> vagrant init centos/7
  7. A `Vagrantfile` has been placed in this directory. You are now
  8. ready to `vagrant up` your first virtual environment! Please read
  9. the comments in the Vagrantfile as well as documentation on
  10. `vagrantup.com` for more information on using Vagrant.
  11. # 可以查看到当前有一个 Vagrantfile 配置文件
  12. E:\centos7> dir
  13. 驱动器 E 中的卷是 Studying
  14. 卷的序列号是 7822-9BE5
  15. E:\centos7 的目录
  16. 2022/11/01 21:17 <DIR> .
  17. 2022/11/01 21:17 3,084 Vagrantfile
  18. 1 个文件 3,084 字节
  19. 1 个目录 406,498,758,656 可用字节
  20. # 启动 vagrant(将VM电源启用)
  21. E:\centos7> vagrant up
  22. # 进入到 vagrant 创建系统的控制台(VM控制台)
  23. E:\centos7> vagrant ssh
  24. # 查看 vagrant 状态
  25. E:\centos7> vagrant status
  26. # vagrant 关机(将VM电源关闭)
  27. E:\centos7> vagrant halt
  28. # vagrant 删除(将VM删除)
  29. E:\centos7> vagrant destroy
命令 作用
vagrant box add 添加box的操作
vagrant init 初始化box的操作,会生成vagrant的配置文件Vagrantfile
vagrant up 启动本地环境
vagrant ssh 通过 ssh 登录本地环境所在虚拟机
vagrant halt 关闭本地环境
vagrant suspend 暂停本地环境
vagrant resume 恢复本地环境
vagrant reload 修改了 Vagrantfile 后,使之生效(相当于先 halt,再 up)
vagrant destroy 彻底移除本地环境
vagrant box list 显示当前已经添加的box列表
vagrant box remove 删除相应的box
vagrant package 打包命令,可以把当前的运行的虚拟机环境进行打包
vagrant plugin 用于安装卸载插件
vagrant status 获取当前虚拟机的状态
vagrant global-status 显示当前用户Vagrant的所有环境状态

:::color2 Error Tip

💫31 Docker Base - 图5

Reference:https://blog.csdn.net/weixin_40230655/article/details/118459738

临时的解决方法:在VirtualBox 中会有相应新建的虚拟机,直接启动后,在利用 <font style="color:#E8323C;">vagrant ssh</font>进行连接即可。[ vagrant 的root 密码是 <font style="color:#E8323C;">vagrant</font> ]

:::

1.3.3.6 VirtualBox for CentOS 7

:::color2 Linux 操作系统需要支持虚拟化功能。

:::

  1. # 1、首先下载用于编译vboxdrv内核模块的必要构建工具:
  2. sudo yum install -y \
  3. kernel-devel \
  4. kernel-devel-$(uname -r) \
  5. kernel-headers \
  6. make patch gcc
  7. # kernel-headers-$(uname -r) \
  8. # 2、/etc/yum.repos.d使用以下wget命令将Oracle Linux repo文件下载到目录:
  9. sudo wget \
  10. https://download.virtualbox.org/virtualbox/rpm/el/virtualbox.repo -P /etc/yum.repos.d
  11. # 3、通过键入以下命令来安装最新版本的VirtualBox 5.2.x:
  12. sudo yum install -y VirtualBox-5.2
  13. # 在安装过程中,系统将提示您导入存储库GPG密钥。输入y并点击Enter。安装完成后,您将看到以下输出:
  14. # Creating group 'vboxusers'. VM users must be member of that group!
  15. #
  16. # Verifying : VirtualBox-5.2-5.2.20_125813_el7-1.x86_64
  17. #
  18. # Installed:
  19. # VirtualBox-5.2.x86_64 0:5.2.20_125813_el7-1
  20. # 4、若要验证VirtualBox安装是否成功,请运行以下命令,该命令将检查vboxdrv服务的状态。
  21. systemctl status vboxdrv
  22. # 输出应类似于以下内容,表明该服务已启用并处于活动状态:
  23. vboxdrv.service - VirtualBox Linux kernel module
  24. Loaded: loaded (/usr/lib/virtualbox/vboxdrv.sh; enabled; vendor preset: disabled)
  25. Active: active (exited) since Wed 2022-11-02 00:06:27 CST; 54s ago
  26. Process: 101240 ExecStart=/usr/lib/virtualbox/vboxdrv.sh start (code=exited, status=0/SUCCESS)
  27. Tasks: 0

💫31 Docker Base - 图6

1.3.3.7 练习

:::color2 使得 Vagrant 启动CentOS 7虚拟机时自动安装 docker 等软件。

:::

  1. # -*- mode: ruby -*-
  2. # vi: set ft=ruby :
  3. # All Vagrant configuration is done below. The "2" in Vagrant.configure
  4. # configures the configuration version (we support older styles for
  5. # backwards compatibility). Please don't change it unless you know what
  6. # you're doing.
  7. Vagrant.configure("2") do |config|
  8. # The most common configuration options are documented and commented below.
  9. # For a complete reference, please see the online documentation at
  10. # https://docs.vagrantup.com.
  11. # Every Vagrant development environment requires a box. You can search for
  12. # boxes at https://vagrantcloud.com/search.
  13. config.vm.box = "centos/7"
  14. # Disable automatic box update checking. If you disable this, then
  15. # boxes will only be checked for updates when the user runs
  16. # `vagrant box outdated`. This is not recommended.
  17. # config.vm.box_check_update = false
  18. # Create a forwarded port mapping which allows access to a specific port
  19. # within the machine from a port on the host machine. In the example below,
  20. # accessing "localhost:8080" will access port 80 on the guest machine.
  21. # NOTE: This will enable public access to the opened port
  22. # config.vm.network "forwarded_port", guest: 80, host: 8080
  23. # Create a forwarded port mapping which allows access to a specific port
  24. # within the machine from a port on the host machine and only allow access
  25. # via 127.0.0.1 to disable public access
  26. # config.vm.network "forwarded_port", guest: 80, host: 8080, host_ip: "127.0.0.1"
  27. # Create a private network, which allows host-only access to the machine
  28. # using a specific IP.
  29. # config.vm.network "private_network", ip: "192.168.33.10"
  30. # Create a public network, which generally matched to bridged network.
  31. # Bridged networks make the machine appear as another physical device on
  32. # your network.
  33. # config.vm.network "public_network"
  34. # Share an additional folder to the guest VM. The first argument is
  35. # the path on the host to the actual folder. The second argument is
  36. # the path on the guest to mount the folder. And the optional third
  37. # argument is a set of non-required options.
  38. # config.vm.synced_folder "../data", "/vagrant_data"
  39. # Provider-specific configuration so you can fine-tune various
  40. # backing providers for Vagrant. These expose provider-specific options.
  41. # Example for VirtualBox:
  42. #
  43. # config.vm.provider "virtualbox" do |vb|
  44. # # Display the VirtualBox GUI when booting the machine
  45. # vb.gui = true
  46. #
  47. # # Customize the amount of memory on the VM:
  48. # vb.memory = "1024"
  49. # end
  50. #
  51. # View the documentation for the provider you are using for more
  52. # information on available options.
  53. # Enable provisioning with a shell script. Additional provisioners such as
  54. # Ansible, Chef, Docker, Puppet and Salt are also available. Please see the
  55. # documentation for more information about their specific syntax and use.
  56. # config.vm.provision "shell", inline: <<-SHELL
  57. # apt-get update
  58. # apt-get install -y apache2
  59. # SHELL
  60. config.vm.provision "shell", inline: <<-SHELL
  61. sudo yum remove docker docker-client docker-client-latest docker-common docker-latest docker-latest-logrotate docker-logrotate docker-engine
  62. sudo yum install -y yum-utils
  63. sudo yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
  64. sudo yum install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
  65. systemctl start docker
  66. SHELL
  67. end

1.4 在Linux系统中安装 Docker

环境准备

  1. 需要会一部分Linux的基础
  2. CentOS 7
  3. 我们可以使用远程连接工具连接远程服务器进行操作!

环境查看

  1. #系统内核是 3.10 以上的
  2. $ uname -r
  3. 3.10.0-1160.el7.x86_64
  1. #系统版本
  2. $ cat /etc/os-release
  3. NAME="CentOS Linux"
  4. VERSION="7 (Core)"
  5. ID="centos"
  6. ID_LIKE="rhel fedora"
  7. VERSION_ID="7"
  8. PRETTY_NAME="CentOS Linux 7 (Core)"
  9. ANSI_COLOR="0;31"
  10. CPE_NAME="cpe:/o:centos:centos:7"
  11. HOME_URL="https://www.centos.org/"
  12. BUG_REPORT_URL="https://bugs.centos.org/"
  13. CENTOS_MANTISBT_PROJECT="CentOS-7"
  14. CENTOS_MANTISBT_PROJECT_VERSION="7"
  15. REDHAT_SUPPORT_PRODUCT="centos"
  16. REDHAT_SUPPORT_PRODUCT_VERSION="7"

安装Docker

帮助文档:

  1. #1.卸载旧的版本
  2. $ sudo yum remove docker \
  3. docker-client \
  4. docker-client-latest \
  5. docker-common \
  6. docker-latest \
  7. docker-latest-logrotate \
  8. docker-logrotate \
  9. docker-engine
  10. #2.需要的安装
  11. $ sudo yum install -y yum-utils
  12. #3.设置镜像的仓库
  13. $ sudo yum-config-manager \
  14. --add-repo \
  15. https://download.docker.com/linux/centos/docker-ce.repo #默认是国外的
  16. $ sudo yum-config-manager \
  17. --add-repo \
  18. https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo #推荐使用阿里云的,速度快
  19. #4.更新yum软件包的索引
  20. $ yum makecache fast
  21. #5.安装Docker相关的 Docker-ce社区版,ee则是企业版
  22. $ sudo yum install -y \
  23. docker-ce docker-ce-cli containerd.io docker-compose-plugin
  24. #6.启动Docker
  25. $ systemctl start docker
  26. #7.查看Docker的信息
  27. $ docker version
  28. #判断Docker是否安装成功
  29. #8.运行helloworld
  30. $ sudo docker run hello-world

💫31 Docker Base - 图7

💫31 Docker Base - 图8

  1. #9.查看镜像是否存在hello-world镜像
  2. $ docker images
  3. REPOSITORY TAG IMAGE ID CREATED SIZE
  4. hello-world latest feb5d9fea6a5 11 months ago 13.3kB
  5. #10.卸载Docker
  6. #卸载依赖
  7. yum remove -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
  8. #删除资源
  9. sudo rm -rf /var/lib/docker
  10. #/var/lib/docker是Docker默认的工作路径
  11. #最新版
  12. sudo rm -rf /var/lib/containerd

1.5 阿里云镜像加速

  1. 登录阿里云找到容器服务
  2. 找到镜像加速地址

💫31 Docker Base - 图9

  1. 配置使用
  1. sudo mkdir -p /etc/docker
  2. sudo tee /etc/docker/daemon.json <<-'EOF'
  3. {
  4. "registry-mirrors": ["https://po13h3y1.mirror.aliyuncs.com","http://hub-mirror.c.163.com","https://mirror.ccs.tencentyun.com","http://f1361db2.m.daocloud.io"],
  5. "exec-opts": ["native.cgroupdriver=systemd"],
  6. "log-driver": "json-file",
  7. "log-opts": {
  8. "max-size": "100m"
  9. },
  10. "storage-driver": "overlay2"
  11. }
  12. EOF
  13. sudo systemctl daemon-reload
  14. sudo systemctl restart docker

2 Docker Machine

[社区]Docker-Machine Document Reference:

https://www.mianshigee.com/tutorial/dockerdocs/userguide-dockermachine.md

2.1 Docker Machine 简介

Docker Machine 是一种可以让您在虚拟主机上安装 Docker 的工具,并可以使用 docker-machine 命令来管理主机。 Docker Machine 也可以集中管理所有的 docker 主机,比如快速的给 100 台服务器安装上 docker。

💫31 Docker Base - 图10

Docker Machine 管理的虚拟主机可以是机上的,也可以是云供应商,如阿里云,腾讯云,AWS,或 DigitalOcean。 使用 docker-machine 命令,您可以启动,检查,停止和重新启动托管主机,也可以升级 Docker 客户端和守护程序,以及配置 Docker 客户端与您的主机进行通信。

💫31 Docker Base - 图11

:::color2 Docker Machine 是一个用于配置和管理带有Docker Engine主机的工具,它允许你在虚拟宿主机上安装Docker,并使用docker-machine命令管理这个宿主机,可以使用Docker Machine在本地的MAC或者windows box、公司网络,数据中心或者AWS这样的云提供商上创建docker。简单说,一个 Docker Machine 就是一个 Docker host 主机和经过配置的 Docker client 的结合体。其作用就是快速帮助我们搭建 Docker 主机环境

:::

2.2 Docker Machine 安装

安装 Docker Machine 之前你需要先安装 Docker。 Docker Machine 可以在多种平台上安装使用,包括 Linux 、MacOS 以及 windows。

Linux 安装命令

  1. base=https://github.com/docker/machine/releases/download/v0.16.0 &&
  2. curl -L $base/docker-machine-$(uname -s)-$(uname -m) >/tmp/docker-machine &&
  3. sudo mv /tmp/docker-machine /usr/local/bin/docker-machine &&
  4. chmod +x /usr/local/bin/docker-machine

macOS 安装命令

  1. base=https://github.com/docker/machine/releases/download/v0.16.0 &&
  2. curl -L $base/docker-machine-$(uname -s)-$(uname -m) >/usr/local/bin/docker-machine &&
  3. chmod +x /usr/local/bin/docker-machine

Windows 安装命令

如果你是 Windows 平台,可以使用 Git BASH,并输入以下命令:
  1. base=https://github.com/docker/machine/releases/download/v0.16.0 &&
  2. mkdir -p "$HOME/bin" &&
  3. curl -L $base/docker-machine-Windows-x86_64.exe > "$HOME/bin/docker-machine.exe" &&
  4. chmod +x "$HOME/bin/docker-machine.exe"
查看是否安装成功:
  1. $ docker-machine version
  2. docker-machine version 0.16.0, build 9371605

:::color2 注意:各版本更新日志里面也有安装说明:https://github.com/docker/machine/releases

:::

2.3 使用 Docker Machine

本章通过 <font style="color:rgb(51, 51, 51);">virtualbox</font> 来介绍 <font style="color:rgb(51, 51, 51);">docker-machine</font> 的使用方法。其他云服务商操作与此基本一致。具体可以参考每家服务商的指导文档。

2.3.1、列出可用的机器

可以看到目前只有这里默认的 default 虚拟机。
  1. $ docker-machine ls

💫31 Docker Base - 图12

2.3.2、创建机器

创建一台名为 test 的机器。
  1. # --driver 可以省略
  2. $ docker-machine create --driver virtualbox test
  • —driver:指定用来创建机器的驱动类型,这里是 virtualbox。

💫31 Docker Base - 图13

2.3.3、查看机器的 ip

  1. $ docker-machine ip test

💫31 Docker Base - 图14

2.3.4、停止机器

  1. $ docker-machine stop test

💫31 Docker Base - 图15

2.3.5、启动机器

  1. $ docker-machine start test

💫31 Docker Base - 图16

2.3.6、进入机器

  1. $ docker-machine ssh test

💫31 Docker Base - 图17

2.4 Docker-Machine 命令参数说明

  • docker-machine active:查看当前激活状态的 Docker 主机。
  1. $ docker-machine ls
  2. NAME ACTIVE DRIVER STATE URL
  3. dev - virtualbox Running tcp://192.168.99.103:2376
  4. staging * digitalocean Running tcp://203.0.113.81:2376
  5. $ echo $DOCKER_HOST
  6. tcp://203.0.113.81:2376
  7. $ docker-machine active
  8. staging
  • config:查看当前激活状态 Docker 主机的连接信息。
  • create:创建 Docker 主机
  • env:显示连接到某个主机需要的环境变量
  • inspect: 以 json 格式输出指定Docker的详细信息
  • ip: 获取指定 Docker 主机的地址
  • kill: 直接杀死指定的 Docker 主机
  • ls: 列出所有的管理主机
  • provision: 重新配置指定主机
  • regenerate-certs: 为某个主机重新生成 TLS 信息
  • restart: 重启指定的主机
  • rm: 删除某台 Docker 主机,对应的虚拟机也会被删除
  • ssh: 通过 SSH 连接到主机上,执行命令
  • scp: 在 Docker 主机之间以及 Docker 主机和本地主机之间通过 scp 远程复制数据
  • mount: 使用 SSHFS 从计算机装载或卸载目录
  • start: 启动一个指定的 Docker 主机,如果对象是个虚拟机,该虚拟机将被启动
  • status: 获取指定 Docker 主机的状态(包括:Running、Paused、Saved、Stopped、Stopping、Starting、Error)等
  • stop: 停止一个指定的 Docker 主机
  • upgrade: 将一个指定主机的 Docker 版本更新为最新
  • url: 获取指定 Docker 主机的监听 URL
  • version: 显示 Docker Machine 的版本或者主机 Docker 版本
  • help: 显示帮助信息

:::color2 扩展:可以使用 docker-machine 的环境变量,将本地的 docker-client 进行连接

:::

  1. $ docker-machine env test
  2. export DOCKER_TLS_VERIFY="1"
  3. export DOCKER_HOST="tcp://192.168.99.100:2376"
  4. export DOCKER_CERT_PATH="/root/.docker/machine/machines/test"
  5. export DOCKER_MACHINE_NAME="test"
  6. # Run this command to configure your shell:
  7. # eval $(docker-machine env test)
  8. # 执行命令
  9. $ eval $(docker-machine env test)
  10. # Server 可以发现是 docker-machine 中 test 的 Server
  11. $ docker version
  12. Client: Docker Engine - Community
  13. Version: 20.10.21
  14. API version: 1.40
  15. Go version: go1.18.7
  16. Git commit: baeda1f
  17. Built: Tue Oct 25 18:04:24 2022
  18. OS/Arch: linux/amd64
  19. Context: default
  20. Experimental: true
  21. Server: Docker Engine - Community
  22. Engine:
  23. Version: 19.03.12
  24. API version: 1.40 (minimum version 1.12)
  25. Go version: go1.13.10
  26. Git commit: 48a66213fe
  27. Built: Mon Jun 22 15:49:35 2020
  28. OS/Arch: linux/amd64
  29. Experimental: false
  30. containerd:
  31. Version: v1.2.13
  32. GitCommit: 7ad184331fa3e55e52b890ea95e65ba581ae3429
  33. runc:
  34. Version: 1.0.0-rc10
  35. GitCommit: dc9208a3303feef5b3839f4323d9beb36df0a9dd
  36. docker-init:
  37. Version: 0.18.0
  38. GitCommit: fec3683

💫31 Docker Base - 图18

2.5 Docker Machine 在 Cloud 中的应用

2.5.1 Docker Machine 在 阿里云上的应用

Video Reference:https://www.bilibili.com/video/BV1xe4y1q7fC/?p=11

Aliyun Driver Reference:https://github.com/AliyunContainerService/docker-machine-driver-aliyunecs

2.5.1.1 概述和Docker安装

Docker-Machine 的使用跟docker入门中一样,只是需要添加阿里云的Docker-Machine 驱动,同时配置阿里云Docker-Machine 驱动的环境。
  1. #!/bin/bash
  2. # Shell ENV
  3. DOCKER_VERSION="20.10.7"
  4. CONTAINERD_VERSION="1.4.6"
  5. # step 1: 安装必要的一些系统工具
  6. echo -e "==> 安装必要的系统工具"
  7. sudo yum install -y yum-utils device-mapper-persistent-data lvm2
  8. # Step 2: 添加软件源信息
  9. echo -e "==> 添加软件源信息"
  10. sudo yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
  11. # Step 3
  12. echo -e "==> 修改配置文件"
  13. sudo sed -i 's+download.docker.com+mirrors.aliyun.com/docker-ce+' /etc/yum.repos.d/docker-ce.repo
  14. # Step 4: 更新并安装Docker-CE
  15. echo -e "==> 安装更新Docker"
  16. sudo yum makecache fast
  17. # containerd.io Docker运行时环境
  18. sudo yum -y install docker-ce-${DOCKER_VERSION} docker-ce-cli-${DOCKER_VERSION} containerd.io-${CONTAINERD_VERSION}
  19. # Step 5: 配置加速器以及docker参数
  20. echo -e "==> 配置加速器以及docker参数"
  21. sudo mkdir -p /etc/docker
  22. sudo tee /etc/docker/daemon.json <<-'EOF'
  23. {
  24. "registry-mirrors": ["https://po13h3y1.mirror.aliyuncs.com","http://hub-mirror.c.163.com","https://mirror.ccs.tencentyun.com","http://f1361db2.m.daocloud.io"],
  25. "exec-opts": ["native.cgroupdriver=systemd"],
  26. "log-driver": "json-file",
  27. "log-opts": {
  28. "max-size": "100m"
  29. },
  30. "storage-driver": "overlay2"
  31. }
  32. EOF
  33. # Step 6: 加载服务
  34. echo -e "==> 加载服务"
  35. sudo systemctl daemon-reload
  36. sudo systemctl restart docker
  37. sudo systemctl enable docker
  38. # 查看Docker服务信息
  39. echo -e "==> 查看Docker服务信息"
  40. docker info

2.5.1.2 Docker-Machine 安装和阿里云 Docker-Machine 驱动

  1. # 安装 Docker Machine 工具
  2. base=https://github.com/docker/machine/releases/download/v0.16.0 &&
  3. curl -L $base/docker-machine-$(uname -s)-$(uname -m) >/tmp/docker-machine &&
  4. sudo mv /tmp/docker-machine /usr/local/bin/docker-machine &&
  5. chmod +x /usr/local/bin/docker-machine
  6. # 1、首先下载用于编译vboxdrv内核模块的必要构建工具:
  7. sudo yum install -y \
  8. kernel-devel \
  9. kernel-devel-$(uname -r) \
  10. kernel-headers \
  11. make patch gcc
  12. # kernel-headers-$(uname -r) \
  13. # 2、/etc/yum.repos.d使用以下wget命令将Oracle Linux repo文件下载到目录:
  14. sudo wget \
  15. https://download.virtualbox.org/virtualbox/rpm/el/virtualbox.repo -P /etc/yum.repos.d
  16. # 3、通过键入以下命令来安装最新版本的VirtualBox 5.2.x:
  17. sudo yum install -y VirtualBox-5.2
  18. # 在安装过程中,系统将提示您导入存储库GPG密钥。输入y并点击Enter。安装完成后,您将看到以下输出:
  19. # Creating group 'vboxusers'. VM users must be member of that group!
  20. #
  21. # Verifying : VirtualBox-5.2-5.2.20_125813_el7-1.x86_64
  22. #
  23. # Installed:
  24. # VirtualBox-5.2.x86_64 0:5.2.20_125813_el7-1
  25. # 4、若要验证VirtualBox安装是否成功,请运行以下命令,该命令将检查vboxdrv服务的状态。
  26. systemctl status vboxdrv
  27. # 输出应类似于以下内容,表明该服务已启用并处于活动状态:
  28. vboxdrv.service - VirtualBox Linux kernel module
  29. Loaded: loaded (/usr/lib/virtualbox/vboxdrv.sh; enabled; vendor preset: disabled)
  30. Active: active (exited) since Wed 2022-11-02 00:06:27 CST; 54s ago
  31. Process: 101240 ExecStart=/usr/lib/virtualbox/vboxdrv.sh start (code=exited, status=0/SUCCESS)
  32. Tasks: 0
  33. # 下载阿里云驱动 Docker-Machine
  34. $ wget https://docker-machine-aliyunecs-drivers.oss-cn-beijing.aliyuncs.com/docker-machine-driver-aliyunecs_linux-amd64.tgz
  35. # 解压压缩包
  36. $ tar -zxvf docker-machine-driver-aliyunecs_linux-amd64.tgz
  37. # 下载之后解压放到bin下面,重命名为 docker-machine-driver-aliyuncs
  38. $ mv bin/docker-machine-driver-aliyunecs.linux-amd64 bin/docker-machine-driver-aliyuncs
  39. # 设置环境变量
  40. # export PATH=<Your Local Path>/docker-machine-driver-aliyuncs[.exe]:$PATH
  41. $ export PATH=/root/bin/:$PATH
  42. # cp bin/docker-machine-driver-aliyuncs /usr/local/bin
  43. # 只是放到下面,是无法执行,因为它其实是个插件,
  44. $ docker-machine create -d aliyunecs -–help
  45. # 执行这个来验证是否成功

💫31 Docker Base - 图19

💫31 Docker Base - 图20

2.5.1.3 配置阿里云Docker-Machine驱动的环境

这个驱动跟docker-machine有类似读取环境变量的行为,环境变量中配置阿里云的API key一类的东西,就可以让docker-machine驱动自动操作我们的阿里云账号购买指定的虚拟机并安装配置相关的环境!花钱更便捷。 找到自己用户目录下的<font style="color:rgb(232, 62, 140);background-color:rgb(246, 246, 246);">.bashrc</font>,在末尾添加如下内容。要在阿里云控制台上找的参数很多,耐心找。
  1. export ECS_ACCESS_KEY_ID='填你自己key id'
  2. export ECS_ACCESS_KEY_SECRET='填你自己的key secret'
  3. # 购买的镜像是1核0.5G内存的最小型实例
  4. export ECS_INSTANCE_TYPE='ecs.t5-lc2m1.nano'
  5. # 来个50M宽带
  6. export ECS_INTERNET_MAX_BANDWIDTH='50'
  7. # 购买的区域是石家庄
  8. export ECS_REGION='cn-zhangjiakou'
  9. # 设置的密码,一定要8~30位,有大小写字母,数字和乱七八糟的标点,不然会自动创建失败
  10. export ECS_SSH_PASSWORD='7b6424B61c6C21~0%39F1C56'
  11. # 磁盘只要20G
  12. export ECS_SYSTEM_DISK_SIZE='20'
  13. # 磁盘用便宜的高效云盘吧,任性选SSD也行
  14. export ECS_SYSTEM_DISK_CATEGORY='cloud_efficiency'
  15. # 选择的镜像是Ubuntu16.04
  16. export ECS_IMAGE_ID='ubuntu_16_0402_64_20G_alibase_20180409.vhd'
  17. # 专用网络的节点
  18. export ECS_VPC_ID='vpc-8vbhii32tpugfcqbryqcn'
  19. # 虚拟交换机的节点
  20. export ECS_VSWITCH_ID='vsw-8vbweep4xrtamazp50775'
  21. # ECS的标签
  22. export ECS_TAGS='chen_docker'
  23. # 安全组
  24. export ECS_SECURITY_GROUP='sg-8vb5wwel08nyrih2lmtb'
  25. # 石家庄a区
  26. export ECS_ZONE='cn-zhangjiakou-a'
  27. # 一定要是true
  28. export ECS_IO_OPTIMIZED='true'

2.5.1.4 阿里云Docker-Machine使用

阿里云操作AccessKey

  • RAM访问控制创建用户

💫31 Docker Base - 图21

  • RAM访问控制获取AccessKey

💫31 Docker Base - 图22

  • 需要将其RAM访问控制的用户权限放通(ECS权限,否则创建失败)
  • 获取AccessKey IDAccessKey Secret

💫31 Docker Base - 图23

  1. AccessKey ID
  2. LTAI5tAatgSRkX4FDhhhXUgm
  3. AccessKey Secret
  4. GjjqZBxKTDvop8h3wB3pakWvi6Sm7L
  1. # 格式:
  2. # docker-machine create -d aliyunecs \
  3. # --aliyunecs-access-key-id=<Your access key ID for the Aliyun ECS API> \
  4. # --aliyunecs-access-key-secret=<Your secret access key for the Aliyun ECS API> \
  5. # --aliyunecs-region=<Region> <machine-name>
  6. # 范例:
  7. docker-machine create -d aliyuncs \
  8. --aliyunecs-io-optimized=optimized \
  9. --aliyunecs-instance-type=ecs.s6-c1m2.small \
  10. --aliyunecs-access-key-id=LTAI5tAatgSRkX4FDhhhXUgm \
  11. --aliyunecs-access-key-secret=GjjqZBxKTDvop8h3wB3pakWvi6Sm7L \
  12. --aliyunecs-region=cn-shenzhen kubesphere

💫31 Docker Base - 图24

:::color5

如果在这里遇到报错<font style="color:rgb(232, 62, 140);background-color:rgb(246, 246, 246);">Error creating machine: Error running provisioning: error installing docker:</font>,先去检查之前让修改的都没有问题之后,再试,如果还是不行,除了docker-machine这台主机,其他两台换为已经安装docker的主机,因为在create的过程中,是通过国外的网站去下载的,网络原因,会下载到一半停止,继续运行create后面的步骤,所以会报这个错误,提前将docker安装好就不会这样了

:::

添加完成后保存并执行<font style="color:rgb(232, 62, 140);background-color:rgb(246, 246, 246);">source .bashrc</font>使配置环境生效。 关于这些参数,阿里云有解释<font style="color:rgb(232, 62, 140);background-color:rgb(246, 246, 246);">https://github.com/AliyunContainerService/docker-machine-driver-aliyunecs</font>

2.5.2 Docker Machine 在 亚马逊AWS上的应用

Video Reference:13.Docker Machine在亚马逊AWS云上的使用-_哔哩哔哩_bilibili

亚马逊AWS 在 Docker Machine 的使用会比阿里云的使用体验要好很多!

2.6 Docker Playgroud

为了帮助你省去繁琐的步骤,在练习过程中,可以直接使用已经搭好的 Docker 学习环境。 首先,进入 Docker Playground。
Docker Playground Reference:

http://labs.play-with-docker.com

https://www.docker.com/play-with-docker/

Playground 将为你虚拟一个学习环境,帮助学习 Docker 的指令、动手操作、并进行小实验。[ 默认是4小时的使用时长 ] 进入页面后,你将看到虚拟出来的一个session(会话)。在左侧点击”添加实例(Add New Instance)”: 它可以提供IP地址、内存、CPU用量等信息。在这个平台上,你可以做一些 docker的操作。例如<font style="color:rgb(77, 77, 77);">docker ps</font>,docker镜像等等。点开小齿轮标志,可看到清空控制台、调节控制台的大小等选项。

:::color2 小总结:

(1)在Mac上玩Docker

  1. Docker for Mac直接装
  2. 通过Virtualbox或者Vmware虚拟化软件直接创建Linux虚拟机,在虚拟机里安装使用Docker
  3. 通过Vagrant + VirtualBox快速搭建Docker host
  4. 通过docker-machine快速搭建Docker host

(2)在Windows上玩Docker

  1. Docker for windows直接装 ( 对系统要求高至少Win10 )
  2. 通过Virtualbox或者Vmware虚拟化软件直接创建Linux虚拟机,在虚拟机里安装使用Docker
  3. 通过Vagrant + VirtualBox快速搭建Docker host
  4. 通过docker-machine快速搭建Docker host

(3)在Linux上玩Docker

  1. Linux主机

  2. Linux虚机(支持虚拟化的任何操作系统或者平台)

(4)在云上玩Docker

  1. Docker-machine + driver ( Aws、Aliyun等 )
  2. 直接使用云服务商提供的容器服务
    1. AWS的ESC (Amazon Elastic Container Service)
    2. Aliyun 的Container Service

:::

3 Docker 架构和底层技术

3.1 Docker 架构和底层技术简介

:::color2 Docker Platform

:::

  • Docker提供了一个开发,打包,运行app的平台
  • 把 app 和底层 infrastructure隔离开来

💫31 Docker Base - 图25

:::color2 Docker Engine

:::

  • 后台进程( dockerd )
  • REST API Server
  • CLI接口( docker )

💫31 Docker Base - 图26

  1. $ docker version
  2. Client: Docker Engine - Community
  3. Version: 20.10.10
  4. API version: 1.41
  5. Go version: go1.16.9
  6. Git commit: b485636
  7. Built: Mon Oct 25 07:44:50 2021
  8. OS/Arch: linux/amd64
  9. Context: default
  10. Experimental: true
  11. Server: Docker Engine - Community
  12. Engine:
  13. Version: 20.10.10
  14. API version: 1.41 (minimum version 1.12)
  15. Go version: go1.16.9
  16. Git commit: e2f740d
  17. Built: Mon Oct 25 07:43:13 2021
  18. OS/Arch: linux/amd64
  19. Experimental: false
  20. containerd:
  21. Version: 1.6.9
  22. GitCommit: 1c90a442489720eec95342e1789ee8a5e1b9536f
  23. runc:
  24. Version: 1.1.4
  25. GitCommit: v1.1.4-0-g5fd4c4d
  26. docker-init:
  27. Version: 0.19.0
  28. GitCommit: de40ad0
  29. $ ps -ef | grep docker
  30. root 1187 1 0 09:28 ? 00:00:01 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
  31. root 2782 1326 0 09:46 pts/0 00:00:00 grep --color=auto docker

:::color2 Docker Architecture

:::

💫31 Docker Base - 图27

  • Docker Client:类似于Linux的命令终端,用于管理Docker资源
  • Docker Daemon:用于管理引擎
  • Docker Image:就是一个只读的模板。镜像可以用来创建 Docker 容器,一个镜像可以创建很多容器。
  • Docker Containers:Docker 利用容器(Container)独立运行的一个或一组应用。容器是用镜像创建的运行实例。可以把容器看做是一个简易版的 Linux 环境(包括root用户权限、进程空间、用户空间和网络空间等)和运行在其中的应用程序。以面向对象的思想可以理解为镜像为类,而容器则是其一个个的实例对象。
  • Docker Network:Docker 的网络隔离是通过 Network Namespace 实现的,不同的网络模式都与 NameSpace 关联。Docker 的网络转发通过 iptables 实现。
  • Docker Volumes:Docker 通过容器数据卷的方式完成数据的持久化的重要资料。[ 完全独立于容器的生命周期,因此Docker不会在容器删除时将其挂载的数据卷删除 ]
  • Docker Registry:Docker仓库(Repository)是集中存放镜像文件的场所。仓库(Repository)和仓库注册服务器(Registry)是有区别的。仓库注册服务器上往往存放着多个仓库,每个仓库中又包含了多个镜像,每个镜像有不同的标签(tag)。仓库分为公开仓库(Public)和私有仓库(Private)两种形式。最大的公开仓库是 Docker Hub ( https://hub.docker.com/ ) ,存放了数量庞大的镜像供用户下载。国内的公开仓库包括阿里云 、网易云 等。

:::color2 Docker 核心架构

:::

💫31 Docker Base - 图28

:::color2 Docker 底层技术支持

:::

  • NameSpace:做隔离,pid,net,ipc,mnt,uts,user
  • Control Groups:做资源限制
  • Union File Systems:Container 和 Image 的分层文件系统[ 联合文件系统 ]
NameSpace 系统调用参数 隔离内容
UTS CLONE_NEWUTS 主机和域名
IPC CLONE_NEWIPC 进程信号量、消息队列和共享内存
PID CLONE_NEWPID 进程编号
Network CLONE_NEWNET 网络设备、网络栈、端口等
Mount CLONE_NEWNS 挂载点(文件系统)
User CLONE_NEWUSER 用户和用户组

3.2 Docker Image 概述

3.2.1 什么是 Image

  • 文件和meta data的集合( root filesystem )
  • 分层的,并且每一层都可以添加改变,删除文件,成为一个新的image
  • 不同的Image可以共享相同的layer
  • Image 本身是 read-only ( 只读 )的

💫31 Docker Base - 图29

  1. $ sudo docker images
  2. REPOSITORY TAG IMAGE ID CREATED SIZE
  3. nginx latest 605c77e624dd 10 months ago 141MB
  4. $ sudo docker image ls
  5. REPOSITORY TAG IMAGE ID CREATED SIZE
  6. nginx latest 605c77e624dd 10 months ago 141MB

3.2.2 Image 的获取(1)

  • Build from Dockerfile
  1. FROM ubuntu:18.04
  2. LABEL maintainer="zhongzhiwei <zhongzhiwei@kubesphere.io>"
  3. RUN apt-get update && apt-get install -y redis-server
  4. EXPOSE 6379
  5. ENTRYPOINT [ "/usr/bin/redis-server" ]
  1. docker build -t zredis:v1.0 -f Dockerfile .

💫31 Docker Base - 图30

3.3.3 Image 的获取(2)

  • Pull from Registry
  1. $ sudo docker pull ubuntu:14.04
  2. 14.04: Pulling from library/ubuntu
  3. 2e6e20c8e2e6: Pull complete
  4. 0551a797c01d: Pull complete
  5. 512123a864da: Pull complete
  6. Digest: sha256:60840958b25b5947b11d7a274274dc48ab32a2f5d18527f5dae2962b64269a3a
  7. Status: Downloaded newer image for ubuntu:14.04
  8. docker.io/library/ubuntu:14.04

:::color2 扩展:使得普通用户可以执行 docker 命令

:::

  1. sudo groupadd docker
  2. sudo usermod -G docker [普通用户]
  3. sudo systemctl restart docker
  4. # 普通可以执行docker的命令

3.3.4 DIY Base Image

  1. $ yum install -y gcc glibc-static
  2. $ mkdir hello-docker ; cd hello-docker
  3. # 编写 C 程序
  4. $ vim hello.c
  5. #include <stdio.h>
  6. int main()
  7. {
  8. printf("hello docker!\n");
  9. }
  10. # 编译并生成可执行文件
  11. $ gcc -static hello.c -o hello
  12. $ ./hello
  13. hello docker!
  14. # 编写 Dockerfile 文件
  15. $ vim Dockerfile
  16. FROM scratch
  17. # Scratch是一个空的Docker镜像。
  18. # 通过scratch来构建一个基础镜像。
  19. LABEL maintainer="zhongzhiwei <zhongzhiwei@kubesphere.io>"
  20. ADD hello /
  21. CMD [ "/hello" ]
  22. # 打包成镜像
  23. $ docker build -t zhongzhiwei/hello-world .
  24. $ docker images
  25. REPOSITORY TAG IMAGE ID CREATED SIZE
  26. zhongzhiwei/hello-world latest 5fbbac5d29a0 37 seconds ago 861kB
  27. $ docker history zhongzhiwei/hello-world
  28. IMAGE CREATED CREATED BY SIZE COMMENT
  29. 5fbbac5d29a0 About a minute ago /bin/sh -c #(nop) CMD ["/hello"] 0B
  30. ec3fad14f2ad About a minute ago /bin/sh -c #(nop) ADD file:061ea1fe9f44c64f7… 861kB
  31. 2a56b96ab165 About a minute ago /bin/sh -c #(nop) LABEL maintainer=zhongzhi… 0B
  32. # 运行成容器
  33. $ docker run -it zhongzhiwei/hello-world
  34. hello docker!

:::color2

使用scratch空镜像的本质是让你的程序只调用host主机的Linux内核部分的功能,而不依赖容器内的操作环境功能。 由于host主机的Linux内核部分对Docker容器是共享的,因此其scratch空镜像的大小可以认为近似为0。 scratch 镜像小总结: 使用scratch空镜像的优点:真正意义上的最小镜像,镜像大小约等于执行文件大小 安全稳定,只需要关注维护程序本身和Linux内核安全更新即可 最高效的资源利用,容器内没有任何多余程序或服务占用资源 制作镜像方便快捷,由于scratch空镜像不需要load或pull就能使用,流水线上制作镜像更加方便快捷 缺点:由于没有sh或bash,无法进入容器内进行交互式调试 PS:该问题实际可以通过构建自定义基础镜像解决。但笔者个人认为生产环境应该通过日志分析问题,而不是进入到容器内进行调试。

:::

3.3 Docker Container

3.3.1 什么是 Container

  • 要有Container首先要有Image,也就是说Container是通过image创建的。
  • Container是在原先的Image之上新加的一层,称作Container layer,这一层是可读可写的(Image是只读的)。
  • 在面向对象的编程语言中,有类跟对象的概念。类是抽象的,对象是类的具体实现。Image跟Container可以类比面向对象中的类跟对象,Image就相当于抽象的类,Container就相当于具体实例化的对象。
  • Image跟Container的职责区别:Image负责APP的存储和分发,Container负责运行APP。

💫31 Docker Base - 图31

3.3.2 Docker 容器操作

  1. $ docker run --help
  2. Usage: docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
  3. Run a command in a new container
  4. ...省略部分输出...
  5. # 列出正在运行的容器
  6. $ docker ps | docker container ls
  7. # 列出所有的容器(正在运行和退出状态)
  8. $ docker ps -a | docker container ls -a
  9. # 运行CentOS 7.9容器
  10. $ docker run -it --name centos-node01 centos:7.9.2009
  11. [root@a6ac274f3e05 /]# ls
  12. anaconda-post.log dev home lib64 mnt proc run srv tmp var
  13. bin etc lib media opt root sbin sys usr
  14. [root@a6ac274f3e05 /]# touch test.txt
  15. [root@a6ac274f3e05 /]# yum install -q -y vim
  16. [root@a6ac274f3e05 /]# exit
  17. # 删除所有的容器
  18. $ docker rm -f $(docker ps -aq)
  19. # 或者使用
  20. $ docker ps -aq | xargs docker rm -f
  21. # 删除正在退出的容器
  22. $ docker rm -f $(docker ps -f "status=exited" -q)

3.3.3 构建 Docker 镜像

:::color2 使用 docker commit 提交成镜像

:::

  1. # 使用 docker commit 将容器提交成一个镜像
  2. $ docker run -it --name centos-node centos:7.9.2009
  3. [root@3b7980304ddd /]# yum install -y -q vim
  4. [root@3b7980304ddd /]# vim --version | head -n 1
  5. VIM - Vi IMproved 7.4 (2013 Aug 10, compiled Dec 15 2020 16:44:08)
  6. $ docker commit \
  7. -a "zhongzhiwei <zhongzhiwei@kubesphere.io>" \
  8. -m "Add software vim" centos-node zhongzhiwei/centos-vim:v1.0
  9. $ docker images
  10. REPOSITORY TAG IMAGE ID CREATED SIZE
  11. zhongzhiwei/centos-vim v1.0 33284aef474e About a minute ago 442MB
  12. $ docker image history zhongzhiwei/centos-vim:v1.0
  13. IMAGE CREATED CREATED BY SIZE COMMENT
  14. 33284aef474e 5 minutes ago /bin/bash 238MB Add software vim
  15. eeb6ee3f44bd 13 months ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B
  16. <missing> 13 months ago /bin/sh -c #(nop) LABEL org.label-schema.sc… 0B
  17. <missing> 13 months ago /bin/sh -c #(nop) ADD file:b3ebbe8bd304723d4… 204MB
  18. $ docker run -it --rm --name centos--test zhongzhiwei/centos-vim:v1.0
  19. [root@a37e65662aa3 /]# vim --version | head -n 1
  20. VIM - Vi IMproved 7.4 (2013 Aug 10, compiled Dec 15 2020 16:44:08)

:::color2 使用 dockerfile 构建镜像

:::

  1. $ mkdir -pv dockerfile/docker-centos-vim ; cd dockerfile/docker-centos-vim
  2. $ vim Dockerfile
  3. FROM centos:7.9.2009 AS baseimg
  4. LABEL maintainer="zhongzhiwei <zhongzhiwei@kubesphere.io>"
  5. # 安装 vim 软件
  6. RUN yum install -y vim
  7. $ docker build -t zhongzhiwei/centos-vim:v2.0 -f Dockerfile .
  8. $ docker images
  9. REPOSITORY TAG IMAGE ID CREATED SIZE
  10. zhongzhiwei/centos-vim v2.0 702ffcff1ca7 15 seconds ago 442MB
  11. $ docker image history zhongzhiwei/centos-vim:v2.0
  12. IMAGE CREATED CREATED BY SIZE COMMENT
  13. 702ffcff1ca7 35 seconds ago /bin/sh -c yum install -y vim 238MB
  14. ef92e80a1b69 2 minutes ago /bin/sh -c #(nop) LABEL maintainer=zhongzhi… 0B
  15. eeb6ee3f44bd 13 months ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B
  16. <missing> 13 months ago /bin/sh -c #(nop) LABEL org.label-schema.sc… 0B
  17. <missing> 13 months ago /bin/sh -c #(nop) ADD file:b3ebbe8bd304723d4… 204MB

3.4 Dockerfile 语法梳理及最佳实践

3.4.1 什么是Dockerfile

官方文档描述:”<font style="color:rgb(0, 0, 0);">Docker can build images automatically by reading the instructions from a </font><font style="color:rgb(232, 62, 140);">Dockerfile</font><font style="color:rgb(0, 0, 0);">. A </font><font style="color:rgb(232, 62, 140);">Dockerfile</font><font style="color:rgb(0, 0, 0);"> is a text document that contains all the commands a user could call on the command line to assemble an image. Using </font><font style="color:rgb(232, 62, 140);">docker build</font><font style="color:rgb(0, 0, 0);"> users can create an automated build that executes several command-line instructions in succession.</font> Dockerfile是由一系列命令和参数构成的脚本,这些命令应用于基础镜像并最终创建一个新的镜像。它们简化了从头到尾的流程并极大的简化了部署工作。Dockerfile从FROM命令开始,紧接着跟随者各种方法,命令和参数。其产出为一个新的可以用于创建容器的镜像。 Dockerfile语法由两部分构成,注释和命令+参数,注释是不能少的,作为一个有自知之明的coder,明天可能就忘记写的是什么玩意了。说白了,Dockerfile是告诉docker怎么样制作一个镜像,就像我们代码写方法告诉应用怎么执行一条逻辑,这样应该好理解了,所以可以在Dockerfile中写明,我们需要怎么个执行方式的某个镜像,最后执行docker build命令构建写好的Dockerfile成镜像。

3.4.2 Dockerfile基础命令

3.4.2.1 FROM

功能为指定基础镜像,并且必须是第一条指令。 如果不以任何镜像为基础,写法为:FROM scratch。 同时意味着接下来所写的指令将作为镜像的第一层开始 语法:

FROM <image> FROM <image>:<tag> FROM <image>:<digest>

三种写法,其中 是可选项,如果没有选择,那么默认值为latest

💫31 Docker Base - 图32

:::color2

FROM 尽量使用官方的 image 作为 base Imge !

:::

3.4.2.2 RUN

功能为运行指定的命令 RUN命令有两种格式
  1. RUN 2. RUN [“executable”, “param1”, “param2”]
第一种后边直接跟shell命令
  1. 在linux操作系统上默认 /bin/sh -c
  2. 在windows操作系统上默认 cmd /S /C
第二种是类似于函数调用。 可将<font style="color:rgb(0, 0, 0);">executable</font>理解成为可执行文件,后面就是两个参数。 两种写法比对:

RUN /bin/bash -c 'source $HOME/.bashrc; echo $HOMERUN ["/bin/bash", "-c", "echo hello"]

注意:多行命令不要写多个RUN,原因是Dockerfile中每一个指令都会建立一层. RUN书写时的换行符是\ 多少个RUN就构建了多少层镜像,会造成镜像的臃肿、多层,不仅仅增加了构件部署的时间,还容易出错。

💫31 Docker Base - 图33

:::color2

RUN 为了美观,复杂的RUN请使用反斜线换行!避免无用分层,合并多条命令成一行! RUN:执行命令并创建新的 Image Layer

:::

3.4.2. CMD

功能为容器启动时要运行的命令 语法有三种写法
  1. CMD [“executable”,”param1”,”param2”] 2. CMD [“param1”,”param2”] 3. CMD command param1 param2
第三种比较好理解了,就时shell这种执行方式和写法 第一种和第二种其实都是可执行文件加上参数的形式 举例说明两种写法:

CMD [ "sh", "-c", "echo $HOME" CMD [ "echo", "$HOME" ]

补充细节:这里边包括参数的一定要用双引号,就是”,不能是单引号, 原因是参数传递后,docker解析的是一个JSON Array

<font style="color:rgb(0, 0, 0);">RUN & CMD</font>

不要把RUN和CMD搞混了。 RUN是构件容器时就运行的命令以及提交运行结果 CMD是容器启动时执行的命令,在构件时并不运行,构件时紧紧指定了这个命令到底是个什么样子。

:::color2

CMD:设置容器启动后默认执行的命令和参数

:::

Shell 和 Exec 格式

💫31 Docker Base - 图34


💫31 Docker Base - 图35

:::color2 在 Dockerfile2 中会发现识别不了 $name 的变量,输出是直接打印,原因:在通过 Shell 格式运行命令,默认会通过 Shell bash 去运行该命令。但是通过 Exec 的格式运行命令,在 Dockerfile2 中是直接运行 echo 的命令,并不是在 Shell 中执行 echo 命令,只是单纯的执行 echo,所以无法识别 $name 变量 。

修正:<font style="color:#2F54EB;">ENTRYPOINT [ "bash", "-c", "echo hello $name" ]</font>

:::

即:

  1. FROM centos:7.9.2009
  2. ENV name Docker
  3. ENTRYPOINT [ "/bin/bash", "-c", "echo hello $name" ]

:::color2

CMD
  • 容器启动时默认执行的命令
  • 如果 docker run 指定了其他命令,CMD命令被忽略
  • 如果定义了多个CMD,只有最后一个会执行

:::

💫31 Docker Base - 图36

docker run [image] 输出?会输出”hello Docker”

docker run -it [image] /bin/bash 输出?不会输出”hello Docker”

3.4.2.3 LABEL

功能是为镜像指定标签 语法:

LABEL <key>=<value> <key>=<value> <key>=<value> ...

一个Dockerfile种可以有多个LABEL,如下:
  1. LABEL "com.example.vendor"="ACME Incorporated"
  2. LABEL com.example.label-with-value="foo"
  3. LABEL version="1.0"
  4. LABEL description="This text illustrates \
  5. that label-values can span multiple lines."
但是并不建议这样写,最好就写成一行,如太长需要换行的话则使用\符号 如下:
  1. LABEL multi.label1="value1" \
  2. multi.label2="value2" \
  3. other="value3"
说明:LABEL会继承基础镜像种的LABEL,如遇到key相同,则值覆盖

💫31 Docker Base - 图37

:::color2

LABEL Metadata 不可少!

:::

3.4.2.4 MAINTAINER

指定作者,不过该语法正在逐渐淘汰。 语法:

MAINTAINER <name>

3.4.2.5 EXPOSE

功能为暴漏容器运行时的监听端口给外部 但是EXPOSE并不会使容器访问主机的端口 如果想使得容器与主机的端口有映射关系,必须在容器启动的时候加上 -P参数

3.4.2.6 ENV

功能为设置环境变量 语法有两种
  1. ENV 2. ENV =
两者的区别就是第一种是一次设置一个,第二种是一次设置多个

💫31 Docker Base - 图38

:::color2

ENV 尽量使用 ENV 增加可维护性!

:::

3.4.2.7 ADD

一个复制命令,把文件复制到镜像中 如果把虚拟机与容器想象成两台linux服务器的话,那么这个命令就类似于scp,只是scp需要加用户名和密码的权限验证,而ADD不用 语法如下:
  1. ADD 2. ADD [““,… ““]
路径的填写可以是容器内的绝对路径,也可以是相对于工作目录的相对路径 可以是一个本地文件或者是一个本地压缩文件,还可以是一个url
  1. #test
  2. FROM ubuntu
  3. MAINTAINER hello
  4. ADD test1.txt test1.txt
  5. ADD test1.txt test1.txt.bak
  6. ADD test1.txt /mydir/
  7. ADD data1 data1
  8. ADD data2 data2
  9. ADD zip.tar /myzip
有如下注意事项: 1、如果源路径是个文件,且目标路径是以 / 结尾, 则docker会把目标路径当作一个目录,会把源文件拷贝到该目录下。 如果目标路径不存在,则会自动创建目标路径。 2、如果源路径是个文件,且目标路径是不是以 / 结尾,则docker会把目标路径当作一个文件。 如果目标路径不存在,会以目标路径为名创建一个文件,内容同源文件; 如果目标文件是个存在的文件,会用源文件覆盖它,当然只是内容覆盖,文件名还是目标文件名。 如果目标文件实际是个存在的目录,则会源文件拷贝到该目录下。 注意,这种情况下,最好显示的以 / 结尾,以避免混淆。 3、如果源路径是个目录,且目标路径不存在,则docker会自动以目标路径创建一个目录,把源路径目录下的文件拷贝进来。 如果目标路径是个已经存在的目录,则docker会把源路径目录下的文件拷贝到该目录下。 4、如果源文件是个归档文件(压缩文件),则docker会自动帮解压。 尽量不要把写成一个文件夹,如果是一个文件夹了,复制整个目录的内容,包括文件系统元数据

3.4.2.8 COPY

看这个名字就知道,又是一个复制命令 语法如下:
  1. COPY 2. COPY [““,… ““]
与ADD的区别, COPY的只能是本地文件,其他用法一致

💫31 Docker Base - 图39

:::color2

ADD or COPY 大部分情况,COPY 优于 ADD! ADD 除了 COPY 还有额外的功能(解压功能)! 添加远程文件 / 目录请使用 curl 或者 wget!

:::

3.4.2.9 ENTRYPOINT

功能是启动时的默认命令 语法如下:
  1. ENTRYPOINT [“executable”, “param1”, “param2”]
  2. ENTRYPOINT command param1 param2
如果从上到下看到这里的话,那么你应该对这两种语法很熟悉啦。 第二种就是写shell 第一种就是可执行文件加参数 与CMD比较说明(这俩命令太像了,而且还可以配合使用): 1. 相同点: 只能写一条,如果写了多条,那么只有最后一条生效 容器启动时才运行,运行时机相同 2. 不同点: ENTRYPOINT不会被运行的command覆盖,而CMD则会被覆盖 如果我们在Dockerfile种同时写了ENTRYPOINT和CMD,并且CMD指令不是一个完整的可执行命令,那么CMD指定的内容将会作为ENTRYPOINT的参数, 如下:
  1. FROM ubuntu
  2. ENTRYPOINT ["top", "-b"]
  3. CMD ["-c"]
如果我们在Dockerfile种同时写了ENTRYPOINT和CMD,并且CMD是一个完整的指令,那么它们两个会互相覆盖,谁在最后谁生效, 如下:
  1. FROM ubuntu
  2. ENTRYPOINT ["top", "-b"]
  3. CMD ls -al
那么将执行ls -al ,top -b不会执行

:::color2

ENTRYPOINT:设置容器启动时运行的命令
  • 让容器以应用程序或者服务的形式运行
  • 不会被忽略,一定会执行
  • 最佳实践,写一个 shell 脚本作为 entrypoint

:::

💫31 Docker Base - 图40

3.4.2.10 VOLUME

可实现挂载功能,可以将内地文件夹或者其他容器种得文件夹挂在到这个容器种 语法为:

VOLUME ["/data"]

说明: [“/data”]可以是一个JsonArray ,也可以是多个值。所以如下几种写法都是正确的
  1. VOLUME ["/var/log/"]
  2. VOLUME /var/log
  3. VOLUME /var/log /var/db
一般的使用场景为需要持久化存储数据时, 容器使用的是AUFS,这种文件系统不能持久化数据,当容器关闭后,所有的更改都会丢失。 所以当数据需要持久化时用这个命令。

3.4.2.11 USER

设置启动容器的用户,可以是用户名或UID,所以,只有下面的两种写法是正确的

USER daemoUSER UID

注意:如果设置了容器以<font style="color:rgb(0, 0, 0);">daemon</font>用户去运行,那么RUN, CMD 和 ENTRYPOINT 都会以这个用户去运行

3.4.2.12 WORKDIR

语法:

WORKDIR /path/to/workdir

设置工作目录,对<font style="color:rgb(0, 0, 0);">RUN,CMD,ENTRYPOINT,COPY,ADD</font>生效。如果不存在则会创建,也可以设置多次。 如:

WORKDIR /a WORKDIR b WORKDIR c RUN pwd

pwd执行的结果是/a/b/c WORKDIR也可以解析环境变量, 如:
  1. ENV DIRPATH /path
  2. WORKDIR $DIRPATH/$DIRNAME
  3. RUN pwd
pwd的执行结果是<font style="color:rgb(0, 0, 0);">/path/$DIRNAME</font> 💫31 Docker Base - 图41 :::color2 WORKDIR 用WORKDIR,不要用 CMD cd!尽量使用绝对目录路径!

:::

3.4.2.13 ARG

语法:

ARG <name>[=<default value>]

设置变量命令,ARG命令定义了一个变量,在docker build创建镜像的时候,使用 <font style="color:rgb(0, 0, 0);">--build-arg <varname>=<value></font>来指定参数 如果用户在build镜像时指定了一个参数没有定义在Dockerfile种,那么将有一个Warning,提示如下:

[Warning] One or more build-args [foo] were not consumed.

我们可以定义一个或多个参数,如下:

FROM busybox ARG user1 ARG buildno ...

也可以给参数一个默认值:

FROM busybox ARG user1=someuser ARG buildno=1 ...

如果我们给了ARG定义的参数默认值,那么当build镜像时没有指定参数值,将会使用这个默认值

3.4.2.14 ONBUILD

语法:

ONBUILD [INSTRUCTION]

这个命令只对当前镜像的子镜像生效。 比如当前镜像为A,在Dockerfile种添加:

ONBUILD RUN ls -al

这个 ls -al 命令不会在A镜像构建或启动的时候执行 此时有一个镜像B是基于A镜像构建的,那么这个ls -al 命令会在B镜像构建的时候被执行。

3.4.2.15 STOPSIGNAL

语法:

STOPSIGNAL signal

STOPSIGNAL 命令是的作用是当容器推出时给系统发送什么样的指令

3.4.2.16 HEALTHCHECK

容器健康状况检查命令 语法有两种:
  1. HEALTHCHECK [OPTIONS] CMD command
  2. HEALTHCHECK NONE
第一个的功能是在容器内部运行一个命令来检查容器的健康状况 第二个的功能是在基础镜像中取消健康检查命令 [OPTIONS]的选项支持以下三中选项:

:::color2

—interval=DURATION 两次检查默认的时间间隔为30秒 —timeout=DURATION 健康检查命令运行超时时长,默认30秒 —retries=N 当连续失败指定次数后,则容器被认为是不健康的,状态为unhealthy,默认次数是3

:::

注意: HEALTHCHECK命令只能出现一次,如果出现了多次,只有最后一个生效。 CMD后边的命令的返回值决定了本次健康检查是否成功,具体的返回值如下:

:::color2

0: success - 表示容器是健康的 1: unhealthy - 表示容器已经不能工作了 2: reserved - 保留值

:::

例子:

HEALTHCHECK --interval=5m --timeout=3s \ CMD curl -f http://localhost/ || exit 1

健康检查命令是:<font style="color:rgb(0, 0, 0);">curl -f http://localhost/ || exit 1</font> , 两次检查的间隔时间是5秒,命令超时时间为3秒

:::color2 总结:

编写Dockerfile的最终目的是基于某些基础镜像进行二次构建为自身所需要的镜像,要学好Dockerfile除了学会基础的指令外,建议多查看docerhub镜像库中各种比较火热的官方镜像Dockerfile,学习当中的优点以及尽可能小的构建镜像。

:::

3.5 镜像的发布

3.5.1 发布镜像到 Dockerhub

DockerHub

  1. DockerHub 地址 https://hub.docker.com/ 注册自己的账号
  2. 确定这个账号可以登录
  3. 在我们服务器上提交自己的镜像
  1. $ docker login --help
  2. Usage: docker login [OPTIONS] [SERVER]
  3. Log in to a Docker registry.
  4. If no server is specified, the default is defined by the daemon.
  5. Options:
  6. -p, --password string Password
  7. --password-stdin Take the password from stdin
  8. -u, --username string Username
  1. 登录完毕后就可以提交镜像了,就是一步 docker push 镜像名:[TAG]

范例:

  1. $ docker login -u "dragonzw" -p "SZzhongaislf"
  2. WARNING! Using --password via the CLI is insecure. Use --password-stdin.
  3. WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
  4. Configure a credential helper to remove this warning. See
  5. https://docs.docker.com/engine/reference/commandline/login/#credentials-store
  6. Login Succeeded
  7. #设置镜像的标签
  8. $ docker tag mytomcat:1.0 dragonzw/tomcat:1.0
  9. #推送镜像到DockerHub
  10. $ docker push dragonzw/tomcat:1.0

💫31 Docker Base - 图42

  1. $ vim hello.c
  2. #include <stdio.h>
  3. int main()
  4. {
  5. printf("hello docker!\n");
  6. }
  7. $ yum install gcc gcc-c++ glibc-static
  8. $ gcc -static hello.c -o hello
  9. $ vim Dockerfile
  10. FROM scratch
  11. LABEL maintainer="zhongzhiwei <zhongzhiwei@kubesphere.io>"
  12. ADD hello /
  13. CMD [ "/hello" ]
  14. $ docker build -t dragonzw/hello-docker:v1.0 -f Dockerfile .
  15. $ docker push dragonzw/hello-docker:v1.0
  16. # 测试
  17. $ docker rmi -f dragonzw/hello-docker:v1.0
  18. # 从 DockerHub中拉取镜像
  19. $ docker pull dragonzw/hello-docker:v1.0

:::color2 通过DockerHub 和 GitHub 做关联,管理员只需要维护 Dockerfile,DockerHub 自动做 docker build 构建

:::

3.5.2 发布镜像到 阿里云

  1. $ sudo docker login --username=dragon志伟 registry.cn-shenzhen.aliyuncs.com
  2. Password:
  3. WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
  4. Configure a credential helper to remove this warning. See
  5. https://docs.docker.com/engine/reference/commandline/login/#credentials-store
  6. Login Succeeded
  7. #重新镜像打标签
  8. #$ docker tag tomcat:[镜像版本号] registry.cn-shenzhen.aliyuncs.com/dragonzw_personal_images/tomcat:[镜像版本号]
  9. $ docker tag mytomcat:1.0 registry.cn-shenzhen.aliyuncs.com/dragonzw_personal_images/tomcat:1.0
  10. #推送镜像
  11. #$ docker push registry.cn-shenzhen.aliyuncs.com/dragonzw_personal_images/tomcat:[镜像版本号]
  12. $ docker push registry.cn-shenzhen.aliyuncs.com/dragonzw_personal_images/tomcat:1.0
  13. #$ docker pull registry.cn-shenzhen.aliyuncs.com/dragonzw_personal_images/tomcat:[镜像版本号]
  14. $ docker pull registry.cn-shenzhen.aliyuncs.com/dragonzw_personal_images/tomcat:1.0

在阿里云个人的镜像仓库就可以查看到 tomcat 的镜像版本。

💫31 Docker Base - 图43

:::warning 阿里云容器镜像就可以参考阿里云官方文档即可。

:::

3.5.3 Docker 私有镜像仓库

  1. # 镜像仓库服务器执行(docker运行)[10.0.0.102]
  2. $ docker run -it -d -p 5000:5000 \
  3. --restart=always --name registry registry:2
  4. # 推送镜像
  5. $ vim hello.c
  6. #include <stdio.h>
  7. int main()
  8. {
  9. printf("hello docker!\n");
  10. }
  11. $ yum install gcc gcc-c++ glibc-static
  12. $ gcc -static hello.c -o hello
  13. $ vim Dockerfile
  14. FROM scratch
  15. LABEL maintainer="zhongzhiwei <zhongzhiwei@kubesphere.io>"
  16. ADD hello /
  17. CMD [ "/hello" ]
  18. $ docker build -t 10.0.0.102:5000/hello-docker:v1.0 -f Dockerfile .
  19. $ vim /etc/docker/daemon.json
  20. {
  21. "registry-mirrors": ["https://po13h3y1.mirror.aliyuncs.com","http://hub-mirror.c.163.com","https://mirror.ccs.tencentyun.com","http://f1361db2.m.daocloud.io"],
  22. "insecure-registries": ["10.0.0.102:5000"]
  23. }
  24. $ systemctl daemon-reload && systemctl restart docker
  25. $ docker push 10.0.0.102:5000/hello-world:v1.0
  26. $ curl -XGET http://10.0.0.102:5000/v2/_catalog
  27. {"repositories":["hello-world"]}
  28. $ curl -XGET http://10.0.0.102:5000/v2/hello-world/tags/list
  29. {"name":"hello-world","tags":["v1.0"]}
  30. $ docker rmi -f 10.0.0.102:5000/hello-world:v1.0
  31. $ docker pull 10.0.0.102:5000/hello-world:v1.0

3.5.4 Dockerfile 实战

  1. $ vim app.py
  2. from flask import Flask
  3. app = Flask(__name__)
  4. @app.route('/')
  5. def hello():
  6. return "hello docker"
  7. if __name__ == '__main__':
  8. app.run()
  9. $ pip install --upgrade pip
  10. $ pip install flask
  11. $ python app.py
  1. FROM python:2.7
  2. LABEL maintainer="zhongzhiwei <zhongzhiwei@kubesphere>"
  3. RUN pip install flask && \
  4. mkdir -pv /app
  5. WORKDIR /app
  6. ADD app.py /app/
  7. CMD [ "python", "app.py" ]
  8. EXPOSE 5000
  1. $ docker build -t flask-demo:v1.0 -f Dockerfile .
  2. $ docker images
  3. REPOSITORY TAG IMAGE ID CREATED SIZE
  4. flask-demo v1.0 7c259632347e 5 seconds ago 906MB
  5. $ docker run -it -d --name flask-node -p 5000:5000 flask-demo:v1.0
  6. $ docker exec -it flask-node sh
  7. # curl localhost:5000
  8. hello docker

  1. $ docker run -it ubuntu
  2. root@045d68516f5f:/# apt update && apt install -y stress
  3. root@045d68516f5f:/# which stress
  4. /usr/bin/stress
  5. # stress 是Linux系统的压力测试工具
  6. root@045d68516f5f:/# stress --help
  7. `stress'' imposes certain types of compute stress on your system
  8. Usage: stress [OPTION [ARG]] ...
  9. -?, --help show this help statement
  10. --version show version statement
  11. -v, --verbose be verbose
  12. -q, --quiet be quiet
  13. -n, --dry-run show what would have been done
  14. -t, --timeout N timeout after N seconds
  15. --backoff N wait factor of N microseconds before work starts
  16. -c, --cpu N spawn N workers spinning on sqrt()
  17. -i, --io N spawn N workers spinning on sync()
  18. -m, --vm N spawn N workers spinning on malloc()/free()
  19. --vm-bytes B malloc B bytes per vm worker (default is 256MB)
  20. --vm-stride B touch a byte every B bytes (default is 4096)
  21. --vm-hang N sleep N secs before free (default none, 0 is inf)
  22. --vm-keep redirty memory instead of freeing and reallocating
  23. -d, --hdd N spawn N workers spinning on write()/unlink()
  24. --hdd-bytes B write B bytes per hdd worker (default is 1GB)
  25. Example: stress --cpu 8 --io 4 --vm 2 --vm-bytes 128M --timeout 10s
  26. Note: Numbers may be suffixed with s,m,h,d,y (time) or B,K,M,G (size).
  27. # 默认是256MB空间
  28. root@045d68516f5f:/# stress --vm 1 -v
  29. root@045d68516f5f:/# stress --vm 1 --vm-bytes 4096MB -v
  1. $ mkdir -pv /root/dockerfile/ubuntu-stress ; cd /root/dockerfile/ubuntu-stress
  2. # 编写Dockerfile文件
  3. $ vim Dockerfile
  4. FROM ubuntu
  5. LABEL maintainer="zhongzhiwei <zhongzhiwei@kubesphere>"
  6. RUN apt update && \
  7. apt install -y stress
  8. ENTRYPOINT [ "/usr/bin/stress" ]
  9. # CMD [ "-v" ]
  10. CMD [ "--vm", "1", "--vm-bytes", "4096MB", "-v" ]
  11. $ docker build -t ubuntu-stress:v1.0 -f Dockerfile .
  12. $ docker run -it -d --name us1 ubuntu-stress:v1.0
  13. $ docker ps -a --no-trunc
  14. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  15. a66a4b6f4e6ba40907b14fa3acf2e2add3e285bae67b13bd73b03d15f632cee0 ubuntu-stress:v1.0 "/usr/bin/stress --vm 1 --vm-bytes 4096MB -v" 6 seconds ago Up 4 seconds us1

3.5.5 小结

💫31 Docker Base - 图44

3.6 容器的操作

  1. # 进入到容器中
  2. $ docker ps
  3. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  4. 3b7980304ddd centos:7.9.2009 "/bin/bash" 8 hours ago Up 8 hours centos-node
  5. $ docker exec -it centos-node /bin/bash
  6. [root@3b7980304ddd /]# cat /etc/redhat-release
  7. CentOS Linux release 7.9.2009 (Core)
  8. [root@3b7980304ddd /]# exit
  9. $ docker exec -it centos-node hostname -I
  10. 172.17.0.2
  11. # 停止容器
  12. $ docker stop centos-node
  13. # 启动容器
  14. $ docker start centos-node
  15. # 运行容器
  16. $ docker run -it -d --restart=always --name centos-demo centos:7.9.2009
  17. $ docker ps
  18. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  19. 4e3fb2992fbc centos:7.9.2009 "/bin/bash" 4 seconds ago Up 2 seconds centos-demo
  20. # 显示容器的详细信息
  21. $ docker inspect centos-demo
  22. # 查看容器的日志
  23. $ docker run -it --restart=always -d --name flask-node flask-demo:v1.0
  24. # -f: 跟踪日志输出
  25. $ docker logs centos-demo
  26. # 查看容器的详细信息显示
  27. $ docker inspect centos-demo
  28. # 可以查看容器ID,创建时间,各种参数,状态,使用的镜像,主机名
  29. # 容器运行是执行的命令,容器的网络
  30. $ docker inspect -f "{{.NetworkSettings}}" centos-demo
  31. # 使用 JSON 格式进行输出
  32. $ docker inspect -f "{{json .NetworkSettings}}" centos-demo

3.7 容器的资源限制

Document Reference:https://www.cnblogs.com/renshengdezheli/p/16662622.html

默认情况下,容器没有资源的使用限制,可以使用主机内核调度程序允许的尽可能多的资源
Docker提供了控制容器使用资源的方法,可以限制容器使用多少内存或 CPU等, 在docker run 命令的运行时配置标志实现资源限制功能

容器的内存限制:

Docker可以强制执行硬性内存限制,即只允许容器使用给定的内存大小

Docker也可以执行非硬性内存限制,即容器可以使用尽可能多的内存,除非内核检测到主机上的内存不够用了

参数 参数解释
-m或者—memory= 容器可以使用的最大内存量。如果设置此选项,则允许的最小值为6m(6 兆字节)。也就是说,您必须将该值设置为至少 6 兆字节。
—memory-swap* 允许此容器交换到磁盘的内存量。
—memory-swappiness 默认情况下,主机内核可以换出容器使用的一定百分比的匿名页面。您可以设置—memory-swappiness为 0 到 100 之间的值,以调整此百分比。
—memory-reservation 允许您指定一个小于—memory在 Docker 检测到主机上的争用或内存不足时激活的软限制。如果使用—memory-reservation,则必须将其设置为低于—memory它才能优先。因为是软限制,所以不保证容器不超过限制。
—kernel-memory 容器可以使用的最大内核内存量。允许的最小值是4m。因为内核内存不能被换出,内核内存不足的容器可能会阻塞主机资源,这会对主机和其他容器产生副作用。
—oom-kill-disable 默认情况下,如果发生内存不足 (OOM) 错误,内核会终止容器中的进程。要更改此行为,请使用该—oom-kill-disable选项。仅在您还设置了该-m/—memory选项的容器上禁用 OOM kill。如果-m未设置该标志,主机可能会耗尽内存,内核可能需要终止主机系统的进程以释放内存。

容器的CPU限制:

默认情况下,每个容器对主机 CPU 周期的访问是无限制的。您可以设置各种约束来限制给定容器对主机 CPU 周期的访问。大多数用户使用和配置 默认的 CFS 调度程序。您还可以配置实时调度程序。 CFS 是用于普通 Linux 进程的 Linux 内核 CPU 调度程序。几个运行时标志允许您配置对容器拥有的 CPU 资源的访问量。当您使用这些设置时,Docker 会修改主机上容器的 cgroup 的设置。
参数 参数解释
—cpus= 指定容器可以使用多少可用 CPU 资源。例如,如果主机有两个 CPU,并且您设置—cpus=”1.5”了 ,则容器最多可以保证一个半的 CPU。这相当于设置—cpu-period=”100000”和—cpu-quota=”150000”。
—cpu-period= 指定 CPU CFS 调度程序周期,它与 —cpu-quota. 默认为 100000 微秒(100 毫秒)。大多数用户不会更改默认设置。对于大多数用例,—cpus是一种更方便的选择。
—cpu-quota= 对容器施加 CPU CFS 配额。—cpu-period容器在被限制之前被限制的每微秒数。因此充当有效上限。对于大多数用例,—cpus是一种更方便的选择。
—cpuset-cpus 限制容器可以使用的特定 CPU 或内核。如果您有多个 CPU,则容器可以使用的逗号分隔列表或连字符分隔的 CPU 范围。第一个 CPU 编号为 0。有效值可能是0-3(使用第一个、第二个、第三个和第四个 CPU)或1,3(使用第二个和第四个 CPU)。
—cpu-shares 将此标志设置为大于或小于默认值 1024 的值,以增加或减少容器的重量,并允许它访问或多或少比例的主机 CPU 周期。这仅在 CPU 周期受到限制时才会强制执行。当有足够多的 CPU 周期可用时,所有容器都会根据需要使用尽可能多的 CPU。这样,这是一个软限制。—cpu-shares不会阻止容器以 swarm 模式调度。它优先考虑可用 CPU 周期的容器 CPU 资源。它不保证或保留任何特定的 CPU 访问权限。
  1. # 限制容器的内存大小
  2. $ docker run -it -d --memory=200M --name u1 ubuntu /bin/bash
  3. # 查看容器的性能指标
  4. $ docker stats u1
  5. CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
  6. c05513160bbb u1 0.00% 896KiB / 200MiB 0.44% 656B / 0B 1.58MB / 0B 1
  7. # 限制CPU的相对权重
  8. $ docker run -itd --cpu-shares=10 --name t1 ubuntu
  9. $ docker run -itd --cpu-shares=5 --name t2 ubuntu
  10. $ docker stats --no-stream t1
  11. CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
  12. c65cbab30a2d t1 0.00% 540KiB / 1.794GiB 0.03% 656B / 0B 0B / 0B 1
  13. $ docker stats --no-stream t2
  14. CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
  15. c6a65f191a7a t2 0.00% 540KiB / 1.794GiB 0.03% 656B / 0B 0B / 0B 1

4 Docker Network 网络

Reference:https://blog.csdn.net/succing/article/details/122433770

💫31 Docker Base - 图45

  • 环境准备
IP地址 主机名 操作系统版本 Docker 版本
10.0.0.101 docker-node01 CentOS Linux release 7.9.2009 Docker 20.10.10
10.0.0.102 docker-node02 CentOS Linux release 7.9.2009 Docker 20.10.10

4.1 基础网络概念

:::color2 基于数据包的通信方式

💫31 Docker Base - 图46

:::

:::color2 网络的分层

💫31 Docker Base - 图47

:::

:::color2 IP地址和路由

💫31 Docker Base - 图48

:::

:::color1 MAC 地址是世界唯一的,IP 地址在局域网每一个设备也是唯一的;IP地址就是逻辑地址,MAC则是真实地址。

IP 地址特点:

  • IP地址具有唯一性,表达性;
  • IP地址是可以修改的地址。
  • IP地址具有可管理的特性。

=============================================================================================

路由(routing)是指分组从源到目的地时,决定端到端路径的网络范围的进程 [1] 。路由工作在OSI参考模型第三层——网络层数据包转发设备。路由器通过转发数据包来实现网络互连。虽然路由器可以支持多种协议(如TCP/IP、IPX/SPXAppleTalk等协议),但是在我国绝大多数路由器运行TCP/IP协议路由器通常连接两个或多个由IP子网或点到点协议标识的逻辑端口,至少拥有1个物理端口。路由器根据收到数据包中的网络层地址以及路由器内部维护的路由表决定输出端口以及下一跳地址,并且重写链路层数据包头实现转发数据包。路由器通过动态维护路由表来反映当前的网络拓扑,并通过网络上其他路由器交换路由和链路信息来维护路由表。

路由表主要构成:

  • Destination:目标网络ID,表示可以到达的目标网络ID,0.0.0.0/0表示所有未知网络,又称为默认路由,优先级最低
  • Genmask:目标网络对应的netmask
  • lface:到达对应网络,应该从当前主机哪个网卡发送出来
  • Gateway:到达非直连的网络;将数据发送到临近(下一个)路由器的临近本主机的接口的IP地址。如果是直连网络。Gateway 是0.0.0.0
  • Metric:开销cost,值越小,路由记录的优先级最高

:::

:::color2 公有IP地址和私有IP地址

Public IP:互联网上的唯一标识,可以访问internet

Private IP:不可在互联网上使用,仅供机构内部使用

  • A类 10.0.0.0—10.255.255.255(10.0.0.0/8)
  • B类 172.16.0.0—172.31.255.255(172.16.0.0/12)
  • C类 192.168.0.0—192.168.255.255 (192.168.0.0/16)

:::

:::color2 网络地址转换NAT

💫31 Docker Base - 图49

:::

:::color2 Ping 和 Telnet

  • Ping(ICMP):验证IP的可达性(可以检查基本的连通性,因为会有禁 Ping 的功能)
  • Telnet:验证服务的可用性

:::

  1. $ ping -c 2 -W 1 www.imooc.com
  2. PING www.imooc.com (120.133.51.67) 56(84) bytes of data.
  3. --- www.imooc.com ping statistics ---
  4. 2 packets transmitted, 0 received, 100% packet loss, time 1000ms
  5. $ telnet www.imooc.com 80
  6. Trying 117.121.101.41...
  7. Connected to www.imooc.com.
  8. Escape character is '^]'.

WireShark 抓包工具可以抓取相应的底层数据包情况。

Reference:

https://github.com/wireshark/wireshark

http://www.wireshark.org

4.2 Linux 网络命名空间

  1. $ docker run -d -it \
  2. --name test1 busybox /bin/sh -c "while true; do sleep 43200 ;done"
  3. $ docker ps
  4. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  5. b07115b7777c busybox "/bin/sh -c 'while t…" 46 seconds ago Up 46 seconds test1
  6. # 当前的网络接口和IP地址
  7. $ docker exec -it test1 ip addr
  8. 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
  9. link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
  10. inet 127.0.0.1/8 scope host lo
  11. valid_lft forever preferred_lft forever
  12. 100: eth0@if101: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
  13. link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
  14. inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
  15. valid_lft forever preferred_lft forever
  16. # 查看宿主机的网络接口和IP地址
  17. $ ip addr
  18. 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
  19. link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
  20. inet 127.0.0.1/8 scope host lo
  21. valid_lft forever preferred_lft forever
  22. inet6 ::1/128 scope host
  23. valid_lft forever preferred_lft forever
  24. 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
  25. link/ether fa:16:3e:6b:c2:03 brd ff:ff:ff:ff:ff:ff
  26. inet 192.168.0.64/24 brd 192.168.0.255 scope global noprefixroute dynamic eth0
  27. valid_lft 61373sec preferred_lft 61373sec
  28. inet6 fe80::f816:3eff:fe6b:c203/64 scope link
  29. valid_lft forever preferred_lft forever
  30. 3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
  31. link/ether 02:42:c5:3b:4b:05 brd ff:ff:ff:ff:ff:ff
  32. inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
  33. valid_lft forever preferred_lft forever
  34. inet6 fe80::42:c5ff:fe3b:4b05/64 scope link
  35. valid_lft forever preferred_lft forever
  36. 101: veth9de4bfa@if100: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default
  37. link/ether 82:ac:0a:b1:70:2b brd ff:ff:ff:ff:ff:ff link-netnsid 0
  38. inet6 fe80::80ac:aff:feb1:702b/64 scope link
  39. valid_lft forever preferred_lft forever
  40. # 创建第二个容器
  41. $ docker run -d -it --name test2 busybox /bin/sh -c "while true; do sleep 43200 ;done"
  42. $ docker exec -it test2 ip addr
  43. 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
  44. link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
  45. inet 127.0.0.1/8 scope host lo
  46. valid_lft forever preferred_lft forever
  47. 102: eth0@if103: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
  48. link/ether 02:42:ac:11:00:03 brd ff:ff:ff:ff:ff:ff
  49. inet 172.17.0.3/16 brd 172.17.255.255 scope global eth0
  50. valid_lft forever preferred_lft forever
  51. # ping 通 test1 的IP地址
  52. $ docker exec -it test2 ping -c1 -W1 172.17.0.2
  53. PING 172.17.0.2 (172.17.0.2): 56 data bytes
  54. 64 bytes from 172.17.0.2: seq=0 ttl=64 time=0.091 ms
  55. --- 172.17.0.2 ping statistics ---
  56. 1 packets transmitted, 1 packets received, 0% packet loss
  57. round-trip min/avg/max = 0.091/0.091/0.091 ms

查看机器的 Network NameSpace

  1. $ ip netns help
  2. Usage: ip netns list
  3. ip netns add NAME
  4. ip netns set NAME NETNSID
  5. ip [-all] netns delete [NAME]
  6. ip netns identify [PID]
  7. ip netns pids NAME
  8. ip [-all] netns exec [NAME] cmd ...
  9. ip netns monitor
  10. ip netns list-id
  11. # 创建 Network NameSpace
  12. $ ip netns add test1
  13. $ ip netns add test2
  14. # 显示 Network NameSpace
  15. $ ip netns list
  16. test1
  17. # 删除 Network NameSpace
  18. $ ip netns delete test1
  19. # 在 Network NameSpace 执行
  20. $ ip netns exec test1 ip addr
  21. 1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1000
  22. link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
  23. # 查看宿主机的 ip link 数据链路层
  24. $ ip link
  25. 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
  26. link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
  27. 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
  28. link/ether fa:16:3e:6b:c2:03 brd ff:ff:ff:ff:ff:ff
  29. 3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default
  30. link/ether 02:42:c5:3b:4b:05 brd ff:ff:ff:ff:ff:ff
  31. # 启用 netns 的lo网卡
  32. $ ip netns exec test1 ip link
  33. 1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1000
  34. link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
  35. $ ip netns exec test1 ip link set dev lo up
  36. $ ip netns exec test1 ip link
  37. 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
  38. link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00

💫31 Docker Base - 图50

使用命令实现 Linux Network Namespace 之间的互联

  1. $ sudo ip link add veth-test1 type veth peer name veth-test2
  2. $ sudo ip link
  3. 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
  4. link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
  5. 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
  6. link/ether fa:16:3e:6b:c2:03 brd ff:ff:ff:ff:ff:ff
  7. 3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default
  8. link/ether 02:42:c5:3b:4b:05 brd ff:ff:ff:ff:ff:ff
  9. 104: veth-test2@veth-test1: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
  10. link/ether d6:80:fb:40:73:7c brd ff:ff:ff:ff:ff:ff
  11. 105: veth-test1@veth-test2: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
  12. link/ether 06:1f:fa:32:e6:2a brd ff:ff:ff:ff:ff:ff
  13. $ sudo ip netns exec test1 ip link
  14. 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
  15. link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
  16. $ sudo ip link set veth-test1 netns test1
  17. $ sudo ip netns exec test1 ip link
  18. 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
  19. link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
  20. 105: veth-test1@if104: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
  21. link/ether 06:1f:fa:32:e6:2a brd ff:ff:ff:ff:ff:ff link-netnsid 0
  22. $ sudo ip link set veth-test2 netns test2
  23. $ sudo ip netns exec test2 ip link
  24. 1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1000
  25. link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
  26. 104: veth-test2@if105: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
  27. link/ether d6:80:fb:40:73:7c brd ff:ff:ff:ff:ff:ff link-netnsid 0
  28. # 就把veth-test2@veth-test1 和 veth-test1@veth-test2添加到相应的网络命名空间中
  29. $ sudo ip link
  30. 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
  31. link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
  32. 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
  33. link/ether fa:16:3e:6b:c2:03 brd ff:ff:ff:ff:ff:ff
  34. 3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default
  35. link/ether 02:42:c5:3b:4b:05 brd ff:ff:ff:ff:ff:ff
  36. # 给veth-test2@veth-test1 和 veth-test1@veth-test2分配IP地址
  37. $ sudo ip netns exec test1 ip addr add 192.168.1.1/24 dev veth-test1
  38. $ sudo ip netns exec test2 ip addr add 192.168.1.2/24 dev veth-test2
  39. # 将接口启用
  40. $ sudo ip netns exec test1 ip link set dev veth-test1 up
  41. $ sudo ip netns exec test2 ip link set dev veth-test2 up
  42. # 查看IP地址是否正常
  43. $ sudo ip netns exec test1 ip addr
  44. 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
  45. link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
  46. inet 127.0.0.1/8 scope host lo
  47. valid_lft forever preferred_lft forever
  48. inet6 ::1/128 scope host
  49. valid_lft forever preferred_lft forever
  50. 105: veth-test1@if104: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
  51. link/ether 06:1f:fa:32:e6:2a brd ff:ff:ff:ff:ff:ff link-netnsid 1
  52. inet 192.168.1.1/24 scope global veth-test1
  53. valid_lft forever preferred_lft forever
  54. inet6 fe80::41f:faff:fe32:e62a/64 scope link
  55. valid_lft forever preferred_lft forever
  56. $ sudo ip netns exec test2 ip addr
  57. 1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1000
  58. link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
  59. 104: veth-test2@if105: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
  60. link/ether d6:80:fb:40:73:7c brd ff:ff:ff:ff:ff:ff link-netnsid 0
  61. inet 192.168.1.2/24 scope global veth-test2
  62. valid_lft forever preferred_lft forever
  63. inet6 fe80::d480:fbff:fe40:737c/64 scope link
  64. valid_lft forever preferred_lft forever
  65. # 检查两个网络命名空间是否互通
  66. $ sudo ip netns exec test1 ping -c1 -W1 192.168.1.2
  67. PING 192.168.1.2 (192.168.1.2) 56(84) bytes of data.
  68. 64 bytes from 192.168.1.2: icmp_seq=1 ttl=64 time=0.088 ms
  69. --- 192.168.1.2 ping statistics ---
  70. 1 packets transmitted, 1 received, 0% packet loss, time 0ms
  71. rtt min/avg/max/mdev = 0.088/0.088/0.088/0.000 ms
  72. $ sudo ip netns exec test2 ping -c1 -W1 192.168.1.1
  73. PING 192.168.1.1 (192.168.1.1) 56(84) bytes of data.
  74. 64 bytes from 192.168.1.1: icmp_seq=1 ttl=64 time=0.036 ms
  75. --- 192.168.1.1 ping statistics ---
  76. 1 packets transmitted, 1 received, 0% packet loss, time 0ms
  77. rtt min/avg/max/mdev = 0.036/0.036/0.036/0.000 ms

4.3 Docker bridge0

:::color1 bridge 模式:使用 docker —network bridge 指定,默认使用 docker0

有些时候对于安全加固,网络通信服务特别设置,有些容器需要跑在指定的网络范围中。

bridge 是动态分配ip日常可以用bridge来部署我们的各种服务。而像注册中心,redis,mysql等等这些需要集群的东西,可以用host共享宿主机ip分配端口来做集群。

:::

  1. $ sudo docker rm -f $(docker ps -qa)
  2. $ sudo docker run -d -it \
  3. --name test1 busybox /bin/sh -c "while true; do sleep 43200 ;done"
  4. # 列出Docker的所有网络
  5. $ sudo docker network ls
  6. NETWORK ID NAME DRIVER SCOPE
  7. 8a2071481321 bridge bridge local
  8. f9b95f3c1bbc host host local
  9. f29d29b46da8 none null local
  10. $ sudo docker ps
  11. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  12. 8926c4b7988a busybox "/bin/sh -c 'while t…" 59 seconds ago Up 58 seconds test1
  13. $ sudo docker network inspect bridge
  14. [
  15. "Name": "bridge",
  16. ...省略部分输出...
  17. "IPAM": {
  18. "Driver": "default",
  19. "Options": null,
  20. "Config": [
  21. {
  22. "Subnet": "172.17.0.0/16"
  23. }
  24. ]
  25. },
  26. ...省略部分输出...
  27. "ConfigOnly": false,
  28. "Containers": {
  29. "8926c4b7988a95e682f089af060589fdc1cdb920d2804428b2ac008ef6129c14": {
  30. "Name": "test1",
  31. "EndpointID": "9cb57fa591dbffa75785a766f60c669394e4928ef80e55af10f59fb67192e3ee",
  32. "MacAddress": "02:42:ac:11:00:02",
  33. "IPv4Address": "172.17.0.2/16",
  34. "IPv6Address": ""
  35. }
  36. },
  37. ...省略部分输出...
  38. }
  39. ]
  40. $ sudo ip addr
  41. 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
  42. link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
  43. inet 127.0.0.1/8 scope host lo
  44. valid_lft forever preferred_lft forever
  45. inet6 ::1/128 scope host
  46. valid_lft forever preferred_lft forever
  47. 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
  48. link/ether fa:16:3e:6b:c2:03 brd ff:ff:ff:ff:ff:ff
  49. inet 192.168.0.64/24 brd 192.168.0.255 scope global noprefixroute dynamic eth0
  50. valid_lft 85718sec preferred_lft 85718sec
  51. inet6 fe80::f816:3eff:fe6b:c203/64 scope link
  52. valid_lft forever preferred_lft forever
  53. 3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
  54. link/ether 02:42:c5:3b:4b:05 brd ff:ff:ff:ff:ff:ff
  55. inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
  56. valid_lft forever preferred_lft forever
  57. inet6 fe80::42:c5ff:fe3b:4b05/64 scope link
  58. valid_lft forever preferred_lft forever
  59. 107: vethde44194@if106: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default
  60. link/ether ca:97:10:8e:a0:59 brd ff:ff:ff:ff:ff:ff link-netnsid 0
  61. inet6 fe80::c897:10ff:fe8e:a059/64 scope link
  62. valid_lft forever preferred_lft forever
  63. $ sudo yum install -y bridge-utils
  64. # 查看bridge网络信息
  65. $ brctl show
  66. bridge name bridge id STP enabled interfaces
  67. docker0 8000.0242c53b4b05 no vethde44194
  68. $ sudo docker run -d -it \
  69. --name test2 busybox /bin/sh -c "while true; do sleep 43200 ;done"
  70. $ sudo docker network inspect bridge
  71. [
  72. {
  73. "Name": "bridge",
  74. ...省略部分输出...
  75. "IPAM": {
  76. "Driver": "default",
  77. "Options": null,
  78. "Config": [
  79. {
  80. "Subnet": "172.17.0.0/16"
  81. }
  82. ]
  83. },
  84. ...省略部分输出...
  85. "ConfigOnly": false,
  86. "Containers": {
  87. "7ac5a81dd21d11553731da609b14eff4b521194d887a4241ea557e32b750f760": {
  88. "Name": "test2",
  89. "EndpointID": "68a546778926c191a734059ad6cf436fef24c700d38b487b2acb2b47437fa62d",
  90. "MacAddress": "02:42:ac:11:00:03",
  91. "IPv4Address": "172.17.0.3/16",
  92. "IPv6Address": ""
  93. },
  94. "8926c4b7988a95e682f089af060589fdc1cdb920d2804428b2ac008ef6129c14": {
  95. "Name": "test1",
  96. "EndpointID": "9cb57fa591dbffa75785a766f60c669394e4928ef80e55af10f59fb67192e3ee",
  97. "MacAddress": "02:42:ac:11:00:02",
  98. "IPv4Address": "172.17.0.2/16",
  99. "IPv6Address": ""
  100. }
  101. },
  102. ...省略部分输出...
  103. }
  104. ]
  105. $ sudo ip addr
  106. 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
  107. link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
  108. inet 127.0.0.1/8 scope host lo
  109. valid_lft forever preferred_lft forever
  110. inet6 ::1/128 scope host
  111. valid_lft forever preferred_lft forever
  112. 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
  113. link/ether fa:16:3e:6b:c2:03 brd ff:ff:ff:ff:ff:ff
  114. inet 192.168.0.64/24 brd 192.168.0.255 scope global noprefixroute dynamic eth0
  115. valid_lft 85413sec preferred_lft 85413sec
  116. inet6 fe80::f816:3eff:fe6b:c203/64 scope link
  117. valid_lft forever preferred_lft forever
  118. 3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
  119. link/ether 02:42:c5:3b:4b:05 brd ff:ff:ff:ff:ff:ff
  120. inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
  121. valid_lft forever preferred_lft forever
  122. inet6 fe80::42:c5ff:fe3b:4b05/64 scope link
  123. valid_lft forever preferred_lft forever
  124. 107: vethde44194@if106: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default
  125. link/ether ca:97:10:8e:a0:59 brd ff:ff:ff:ff:ff:ff link-netnsid 0
  126. inet6 fe80::c897:10ff:fe8e:a059/64 scope link
  127. valid_lft forever preferred_lft forever
  128. 109: veth176c34f@if108: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default
  129. link/ether d2:9d:24:68:5a:9a brd ff:ff:ff:ff:ff:ff link-netnsid 1
  130. inet6 fe80::d09d:24ff:fe68:5a9a/64 scope link
  131. valid_lft forever preferred_lft forever
  132. $ brctl show
  133. bridge name bridge id STP enabled interfaces
  134. docker0 8000.0242c53b4b05 no veth176c34f
  135. vethde44194

:::color5 Bridge Network

:::

💫31 Docker Base - 图51

4.4 Container Link 网络模式

容器间如果想通过容器名进行网络连接,需要使用 docker run —link 来链接两个容器。 –link可以用来链接2个容器,使得源容器(被链接的容器)和接收容器(主动去链接的容器)之间可以互相通信,并且接收容器可以获取源容器的一些数据,如源容器的环境变量。

:::color5

–link 的格式

:::

  1. --link <name or id>:alias
–link 添加到另一个容器的链接 name和id是源容器的name和id,alias是源容器在link下的别名。

范例:使用 docker —link

  1. $ docker rm -f $(docker ps -qa)
  2. $ docker run -d -it --name test1 \
  3. busybox /bin/sh -c "while true; do sleep 43200 ;done"
  4. $ docker exec -it test1 ip addr
  5. 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
  6. link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
  7. inet 127.0.0.1/8 scope host lo
  8. valid_lft forever preferred_lft forever
  9. 106: eth0@if107: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
  10. link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
  11. inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
  12. $ docker run -it -d --name test2 \
  13. --link test1 busybox /bin/sh -c "while true; do sleep 43200 ;done"
  14. # 进入到 test2 的终端
  15. $ docker exec -it test2 /bin/sh
  16. / # ping -c1 -W1 172.17.0.2
  17. PING 172.17.0.2 (172.17.0.2): 56 data bytes
  18. 64 bytes from 172.17.0.2: seq=0 ttl=64 time=0.110 ms
  19. --- 172.17.0.2 ping statistics ---
  20. 1 packets transmitted, 1 packets received, 0% packet loss
  21. round-trip min/avg/max = 0.110/0.110/0.110 ms
  22. # 因为有 --link 模式,所以可以通过容器名进行互通
  23. / # ping -c1 -W1 test1
  24. PING test1 (172.17.0.2): 56 data bytes
  25. 64 bytes from 172.17.0.2: seq=0 ttl=64 time=0.074 ms
  26. --- test1 ping statistics ---
  27. 1 packets transmitted, 1 packets received, 0% packet loss
  28. round-trip min/avg/max = 0.074/0.074/0.074 ms
  29. # 但是 test1 并不能通过容器名ping通 test2
  30. $ docker exec -it test1 ping -c1 -W1 test2
  31. ping: bad address 'test2'
  32. # 所以这种 --link 的方式使用并不多,而是使用 docker 的自定义网络来实现

使用自定义网络来实现( Bridge网络模式 )

  1. $ sudo docker network create --driver bridge my-bridge
  2. $ sudo docker network ls
  3. NETWORK ID NAME DRIVER SCOPE
  4. 8a2071481321 bridge bridge local
  5. f9b95f3c1bbc host host local
  6. 83e74a0a1a41 my-bridge bridge local
  7. f29d29b46da8 none null local
  8. $ sudo brctl show
  9. bridge name bridge id STP enabled interfaces
  10. br-83e74a0a1a41 8000.0242ecd098c7 no
  11. docker0 8000.0242c53b4b05 no veth72e2a58
  12. vethde44194
  13. $ sudo docker run -it -d --name test3 --network my-bridge busybox /bin/sh -c "while true; do sleep 43200 ;done"
  14. $ sudo brctl show
  15. bridge name bridge id STP enabled interfaces
  16. br-83e74a0a1a41 8000.0242ecd098c7 no vethba62779
  17. docker0 8000.0242c53b4b05 no veth72e2a58
  18. vethde44194
  19. $ sudo docker network inspect my-bridge
  20. [
  21. {
  22. "Name": "my-bridge",
  23. ...省略部分输出...
  24. "IPAM": {
  25. "Driver": "default",
  26. "Options": {},
  27. "Config": [
  28. {
  29. "Subnet": "172.18.0.0/16",
  30. "Gateway": "172.18.0.1"
  31. }
  32. ]
  33. },
  34. ...省略部分输出...
  35. "ConfigOnly": false,
  36. "Containers": {
  37. "c481f1bb7264f07dca8d9882065add891889b97351f51e14143b9fcf35bd9304": {
  38. "Name": "test3",
  39. "EndpointID": "1067372fcd34f72b0705c2e077a6d1e611cd844ea024d83d883d305a1ad8f905",
  40. "MacAddress": "02:42:ac:12:00:02",
  41. "IPv4Address": "172.18.0.2/16",
  42. "IPv6Address": ""
  43. }
  44. },
  45. ...省略部分输出...
  46. }
  47. ]
  48. # 使用 network connect 的参数将容器跟相应的 network 互联
  49. $ sudo docker network connect my-bridge test2
  50. $ sudo docker network inspect my-bridge
  51. [
  52. {
  53. "Name": "my-bridge",
  54. ...省略部分输出...
  55. "IPAM": {
  56. "Driver": "default",
  57. "Options": {},
  58. "Config": [
  59. {
  60. "Subnet": "172.18.0.0/16",
  61. "Gateway": "172.18.0.1"
  62. }
  63. ]
  64. },
  65. ...省略部分输出...
  66. "ConfigOnly": false,
  67. "Containers": {
  68. "c481f1bb7264f07dca8d9882065add891889b97351f51e14143b9fcf35bd9304": {
  69. "Name": "test3",
  70. "EndpointID": "1067372fcd34f72b0705c2e077a6d1e611cd844ea024d83d883d305a1ad8f905",
  71. "MacAddress": "02:42:ac:12:00:02",
  72. "IPv4Address": "172.18.0.2/16",
  73. "IPv6Address": ""
  74. },
  75. "d620be4657a8d7c7eb489a6165685e91e98a12e823cdc11230523beab6627c88": {
  76. "Name": "test2",
  77. "EndpointID": "bd242396d4118d3ba9c77199377865ad2ca128616ad4b275bca01c730a2d7586",
  78. "MacAddress": "02:42:ac:12:00:03",
  79. "IPv4Address": "172.18.0.3/16",
  80. "IPv6Address": ""
  81. }
  82. },
  83. ...省略部分输出...
  84. }
  85. ]
  86. # test2 容器的网络接口有默认的bridge 和 my-bridge自定义网络
  87. $ sudo docker exec -it test2 ip addr
  88. 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
  89. link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
  90. inet 127.0.0.1/8 scope host lo
  91. valid_lft forever preferred_lft forever
  92. 110: eth0@if111: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
  93. link/ether 02:42:ac:11:00:03 brd ff:ff:ff:ff:ff:ff
  94. inet 172.17.0.3/16 brd 172.17.255.255 scope global eth0
  95. valid_lft forever preferred_lft forever
  96. 115: eth1@if116: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
  97. link/ether 02:42:ac:12:00:03 brd ff:ff:ff:ff:ff:ff
  98. inet 172.18.0.3/16 brd 172.18.255.255 scope global eth1
  99. valid_lft forever preferred_lft forever
  100. # test2 容器通信 test3 的IP地址和主机名
  101. $ sudo docker exec -it test2 ping -c1 -W1 172.18.0.2
  102. PING 172.18.0.2 (172.18.0.2): 56 data bytes
  103. 64 bytes from 172.18.0.2: seq=0 ttl=64 time=0.103 ms
  104. --- 172.18.0.2 ping statistics ---
  105. 1 packets transmitted, 1 packets received, 0% packet loss
  106. round-trip min/avg/max = 0.103/0.103/0.103 ms
  107. $ sudo docker exec -it test2 ping -c1 -W1 test3
  108. PING test3 (172.18.0.2): 56 data bytes
  109. 64 bytes from 172.18.0.2: seq=0 ttl=64 time=0.059 ms
  110. --- test3 ping statistics ---
  111. 1 packets transmitted, 1 packets received, 0% packet loss
  112. round-trip min/avg/max = 0.059/0.059/0.059 ms
  113. # test3 容器通信 test2 的IP地址和主机名
  114. $ sudo docker exec -it test3 ping -c1 -W1 172.18.0.3
  115. PING 172.18.0.3 (172.18.0.3): 56 data bytes
  116. 64 bytes from 172.18.0.3: seq=0 ttl=64 time=0.079 ms
  117. --- 172.18.0.3 ping statistics ---
  118. 1 packets transmitted, 1 packets received, 0% packet loss
  119. round-trip min/avg/max = 0.079/0.079/0.079 ms
  120. $ sudo docker exec -it test3 ping -c1 -W1 test2
  121. PING test2 (172.18.0.3): 56 data bytes
  122. 64 bytes from 172.18.0.3: seq=0 ttl=64 time=0.060 ms
  123. --- test2 ping statistics ---
  124. 1 packets transmitted, 1 packets received, 0% packet loss
  125. round-trip min/avg/max = 0.060/0.060/0.060 ms

4.5 网络端口映射

  1. $ sudo docker run -it -d --name web01 nginx
  2. # 不做端口映射要想访问nginx页面,需要进入到nginx容器中
  3. $ docker exec -it web01 /bin/bash
  4. root@46eda4530967:/# curl 127.0.0.1
  5. <!DOCTYPE html>
  6. <html>
  7. <head>
  8. <title>Welcome to nginx!</title>
  9. <style>
  10. html { color-scheme: light dark; }
  11. body { width: 35em; margin: 0 auto;
  12. font-family: Tahoma, Verdana, Arial, sans-serif; }
  13. </style>
  14. </head>
  15. <body>
  16. <h1>Welcome to nginx!</h1>
  17. <p>If you see this page, the nginx web server is successfully installed and
  18. working. Further configuration is required.</p>
  19. <p>For online documentation and support please refer to
  20. <a href="http://nginx.org/">nginx.org</a>.<br/>
  21. Commercial support is available at
  22. <a href="http://nginx.com/">nginx.com</a>.</p>
  23. <p><em>Thank you for using nginx.</em></p>
  24. </body>
  25. </html>
  26. $ docker ps --no-trunc
  27. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  28. 46eda4530967606eeaefcae3e9f2597d7b4ad4c0becd6b0898f8768273233c3a nginx "/docker-entrypoint.sh nginx -g 'daemon off;'" 4 minutes ago Up 4 minutes 80/tcp web01
  29. # 查看容器的IP地址
  30. $ docker inspect -f "{{.NetworkSettings.IPAddress}}" web01
  31. 172.17.0.4
  32. $ curl 172.17.0.4
  33. <!DOCTYPE html>
  34. <html>
  35. <head>
  36. <title>Welcome to nginx!</title>
  37. <style>
  38. html { color-scheme: light dark; }
  39. body { width: 35em; margin: 0 auto;
  40. font-family: Tahoma, Verdana, Arial, sans-serif; }
  41. </style>
  42. </head>
  43. <body>
  44. <h1>Welcome to nginx!</h1>
  45. <p>If you see this page, the nginx web server is successfully installed and
  46. working. Further configuration is required.</p>
  47. <p>For online documentation and support please refer to
  48. <a href="http://nginx.org/">nginx.org</a>.<br/>
  49. Commercial support is available at
  50. <a href="http://nginx.com/">nginx.com</a>.</p>
  51. <p><em>Thank you for using nginx.</em></p>
  52. </body>
  53. </html>
  54. $ telnet 172.17.0.4 80
  55. Trying 172.17.0.4...
  56. Connected to 172.17.0.4.
  57. Escape character is '^]'.
  58. # 容器的端口的映射(-p 宿主机端口:容器端口)
  59. $ docker run -it -d --name web01 -p 80:80 nginx
  60. $ docker ps
  61. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  62. 8482453167f6 nginx "/docker-entrypoint.…" 2 minutes ago Up 2 minutes 0.0.0.0:80->80/tcp, :::80->80/tcp web01
  63. # 使用宿主机的端口进行访问
  64. $ ip addr
  65. 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
  66. link/ether fa:16:3e:6b:c2:03 brd ff:ff:ff:ff:ff:ff
  67. inet 192.168.0.64/24 brd 192.168.0.255 scope global noprefixroute dynamic eth0
  68. valid_lft 83173sec preferred_lft 83173sec
  69. inet6 fe80::f816:3eff:fe6b:c203/64 scope link
  70. valid_lft forever preferred_lft forever
  71. $ curl 192.168.0.64
  72. <!DOCTYPE html>
  73. <html>
  74. <head>
  75. <title>Welcome to nginx!</title>
  76. <style>
  77. html { color-scheme: light dark; }
  78. body { width: 35em; margin: 0 auto;
  79. font-family: Tahoma, Verdana, Arial, sans-serif; }
  80. </style>
  81. </head>
  82. <body>
  83. <h1>Welcome to nginx!</h1>
  84. <p>If you see this page, the nginx web server is successfully installed and
  85. working. Further configuration is required.</p>
  86. <p>For online documentation and support please refer to
  87. <a href="http://nginx.org/">nginx.org</a>.<br/>
  88. Commercial support is available at
  89. <a href="http://nginx.com/">nginx.com</a>.</p>
  90. <p><em>Thank you for using nginx.</em></p>
  91. </body>
  92. </html>
  93. # 因为使用的华为云服务器,可以访问其公网的IP地址的80端口
  94. # 云服务器的安全组需要将其放通相应的宿主机的映射端口
  95. $ curl 110.41.20.249

💫31 Docker Base - 图52

:::color5 Container Port Map

:::

💫31 Docker Base - 图53

4.6 网络模式之 host 和 none

:::color5 none 网络模式:

:::

禁用了网络功能,只有 lo 标识(就是127.0.0.1表示本地回环地址)。

在 none 模式下,并不为 Docker 容器进行任何网络配置;也就是说,这个Docker 容器没有网卡、IP、路由等信息,只有loopback(lo);需要自己为Docker容器添加网卡,配置IP等。

  1. $ docker network ls
  2. NETWORK ID NAME DRIVER SCOPE
  3. 8a2071481321 bridge bridge local
  4. f9b95f3c1bbc host host local
  5. 83e74a0a1a41 my-bridge bridge local
  6. f29d29b46da8 none null local
  7. # 使用 none 网络模式
  8. $ docker run -it -d --name test1 --network none busybox /bin/sh -c "while true; do sleep 43200 ;done"
  9. $ docker exec -it test1 /bin/sh
  10. # 只有 一张 lo 回环网卡
  11. / # ip addr
  12. 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
  13. link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
  14. inet 127.0.0.1/8 scope host lo
  15. valid_lft forever preferred_lft forever
  16. # none 网络模式应用场景
  17. # 用于保存安全性较高的数据的容器

:::color5 host 网络模式:

:::

直接使用宿主机的IP地址与外界进行通信,不再需要额外进行NAT转换。

  1. $ docker run -it -d --name test2 --network host busybox /bin/sh -c "while true; do sleep 43200 ;done"
  2. $ docker exec -it test2 /bin/sh
  3. # 可以查看到宿主机的网络命名空间
  4. / # ip addr
  5. 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
  6. link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
  7. inet 127.0.0.1/8 scope host lo
  8. valid_lft forever preferred_lft forever
  9. inet6 ::1/128 scope host
  10. valid_lft forever preferred_lft forever
  11. 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast qlen 1000
  12. link/ether fa:16:3e:6b:c2:03 brd ff:ff:ff:ff:ff:ff
  13. inet 192.168.0.64/24 brd 192.168.0.255 scope global dynamic noprefixroute eth0
  14. valid_lft 82202sec preferred_lft 82202sec
  15. inet6 fe80::f816:3eff:fe6b:c203/64 scope link
  16. valid_lft forever preferred_lft forever
  17. 3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue
  18. link/ether 02:42:c5:3b:4b:05 brd ff:ff:ff:ff:ff:ff
  19. inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
  20. valid_lft forever preferred_lft forever
  21. inet6 fe80::42:c5ff:fe3b:4b05/64 scope link
  22. valid_lft forever preferred_lft forever
  23. 112: br-83e74a0a1a41: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue
  24. link/ether 02:42:ec:d0:98:c7 brd ff:ff:ff:ff:ff:ff
  25. inet 172.18.0.1/16 brd 172.18.255.255 scope global br-83e74a0a1a41
  26. valid_lft forever preferred_lft forever
  27. inet6 fe80::42:ecff:fed0:98c7/64 scope link
  28. valid_lft forever preferred_lft forever
  29. # 缺点:可能会出现相应的端口冲突的问题。

案例

  • 说明

容器将不会获得一个独立的 Network NameSpace,而是和宿主机共用一个 Network NameSpace。<font style="color:#F5222D;">容器将不会虚拟出自己的网卡而是使用宿主机的IP和端口。</font>

💫31 Docker Base - 图54

代码

  • 警告
  1. $ docker run -d -p 8083:8080 --network host --name tomcat83 billygoo/tomcat8-jdk8
  2. # WARNING: Published ports are discarded when using host network mode
  3. # 当使用host网络模式的时候,Published发布的端口是不被推荐的
  4. # 问题:docker 启动时总是遇到标题中的警告
  5. # 原因:
  6. docker 启动时指定 --network=host 或者 -net host,如果还指定了 -p 映射端口,那么这个时候会有此警告,并且通过 -p 设置的参数将不会起到任何作用,端口号会以主机端口号为主,重复时则会递增。
  7. # 解决:
  8. 解决的方法就是使用 docker 的其他网络模式,例如 --network=bridge,这样就可以解决问题,或者直接无视。
  9. $ docker ps
  10. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  11. 819798960a6a billygoo/tomcat8-jdk8 "catalina.sh run" 3 minutes ago Up 3 minutes tomcat83
  • 正确
  1. $ docker run -d --network host --name tomcat83 billygoo/tomcat8-jdk8

4.7 总结:

网络模型 简介
bridge 为每一个容器分配、设置IP等,并将容器连接到一个<font style="color:#E8323C;">docker0</font>虚拟网桥,默认为该模式
host 容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口
none 容器有独立的 Network Namespace(网络名称空间),但是并没有对其进行任何网络设置,如分配 veth pair 和网桥连接,IP等。(基本上不会使用)
container 新创建的容器不会创建自己的网卡和配置自己的IP,而是和一个指定的容器共享IP,端口范围等

docker network 主流的是 bridge、host、none,常用的是 bridge、host。

4.8 多容器复杂应用的部署

  1. # 基础版
  2. $ vim app.py
  3. from flask import Flask
  4. app = Flask(__name__)
  5. @app.route('/')
  6. def hello():
  7. return "hello docker"
  8. if __name__ == '__main__':
  9. app.run()
  10. # 升级版
  11. $ vim app.py
  12. import os
  13. import socket
  14. from flask import Flask
  15. from redis.client import Redis
  16. app = Flask(__name__)
  17. redis = Redis(host=os.environ.get('REDIS_HOST', '127.0.0.1'), port=6379)
  18. @app.route('/')
  19. def hello():
  20. redis.incr('hits')
  21. return 'Hello Container World! I have been seen %s times and my hostname is %s.\n' % (
  22. redis.get('hits'), socket.gethostname())
  23. if __name__ == "__main__":
  24. app.run(host="0.0.0.0", port=5000, debug=True)
  1. FROM python:2.7
  2. LABEL maintainer="zhongzhiwei <zhongzhiwei@kubesphere.io>"
  3. RUN mkdir -p /app && \
  4. pip install flask redis
  5. WORKDIR /app
  6. COPY . /app
  7. EXPOSE 5000
  8. CMD [ "python", "app.py" ]
  1. # 启动 Redis 容器
  2. $ docker run -it -d --name redis redis
  3. $ docker build -t flask-redis:v1.0 -f Dockerfile .
  4. # 启动 flask-redis 容器( -e 设置环境变量)
  5. $ docker run -it -d --name flask-redis --link redis -e REDIS_HOST=redis flask-redis:v1.0
  6. $ docker exec -it flask-redis /bin/bash
  7. root@0a1d7b16c43f:/app# echo $REDIS_HOST
  8. redis
  9. root@0a1d7b16c43f:/app# curl 127.0.0.1:5000
  10. Hello Container World! I have been seen 1 times and my hostname is 0a1d7b16c43f.
  11. root@0a1d7b16c43f:/app# curl 127.0.0.1:5000
  12. Hello Container World! I have been seen 2 times and my hostname is 0a1d7b16c43f.
  13. # 做端口映射
  14. $ docker rm -f flask-redis
  15. $ docker run -it -d --name flask-redis -p 5000:5000 --link redis -e REDIS_HOST=redis flask-redis:v1.0
  16. # 再次访问
  17. $ curl 127.0.0.1:5000
  18. Hello Container World! I have been seen 3 times and my hostname is b02030a3c3ea.
  19. $ curl 127.0.0.1:5000
  20. Hello Container World! I have been seen 4 times and my hostname is b02030a3c3ea.

💫31 Docker Base - 图55

设置容器的环境变量

  1. $ docker run -it -d --name test1 \
  2. -e NAME="zhongzhiwei" \
  3. -e EMAIL="zhongzhiwei@kubesphere.io" \
  4. busybox /bin/sh -c "while true; do sleep 43200 ;done"
  5. $ docker exec -it test1 /bin/sh
  6. / # env
  7. HOSTNAME=b5df0d82748d
  8. SHLVL=1
  9. HOME=/root
  10. NAME=zhongzhiwei
  11. TERM=xterm
  12. PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
  13. EMAIL=zhongzhiwei@kubesphere.io
  14. PWD=/

多机器的通信?

💫31 Docker Base - 图56

4.9 Overlay 和 Underlay

Reference:https://www.jianshu.com/p/d34d6a684d34?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

4.9.1 Overlay 和 Underlay 解释

伴随着网络技术的发展,数据中心的二层组网结构出现了阶段性的架构变化,数据中心网络分为了Underlay和Overlay两个部分,网络进入了Overlay虚拟化阶段。那么Overlay网络是如何形成的?与Underlay 有哪些区别?又试图解决什么问题?

Underlay网络

Underlay 网络是负责传递数据包的物理网络,由交换机和路由器等设备组成,借助以太网协议、路由协议和VLAN协议等驱动。Underlay的所有网络组件都必须通过使用路由协议来确定 IP 连接。 对Underlay 网络而言,需要建立一个设计良好的L3,包括园区边缘交换机等,以确保网络的性能、可扩展性和高可用性。 Underlay协议:BGP、OSPF、IS-IS、EIGRP Overlay网络 Overlay 是使用网络虚拟化在物理基础设施之上建立连接的逻辑网络。与UnderLay网络相比,Overlay实现了控制平面与转发平面的分离,这也是SDN的核心理念。 💫31 Docker Base - 图57 VXLAN协议是目前最流行的Overlay网络隧道协议之一,它是由IETF定义的NVO3(Network Virtualization over Layer 3)标准技术之一,采用L2 over L4(MAC-in-UDP)的报文封装模式,将二层报文用三层协议进行封装,可实现二层网络在三层范围内进行扩展,将“二层域”突破规模限制形成“大二层域”。 通过OverLay技术,可以在对物理网络不做任何改造的情况下,通过隧道技术在现有的物理网络上创建了一个或多个逻辑网络,有效解决物理数据中心存在的诸多问题,实现了数据中心的自动化和智能化。 Overlay协议:VXLAN、NVGRE、GRE、OTV、OMP、mVPN Underlay网络的一些限制 传统路由协议构建了路由前缀列表,每个路由条目都指向下一跳的 IP 地址。这意味着每个数据包都会根据路由表在网络中逐跳转发到目的地。这种逐跳路由行为有许多低效之处,例如: 1)网络分段和网络切片很难大规模实现: + 在网络中逐跳传输分段标签需要 VRF、MPLS 和 MP-BGP 之间进行复杂的控制平面交互。 + 网络切片和多租户无法实现。 2)多路径转发繁琐,无法融合多个底层网络来实现负载均衡。 3)服务链无法有效扩展,因为它需要在多个设备上进行手动配置。 4)互联网不能保证私密通信的安全要求。 Underlay网络存在着以上诸多限制,而Overlay带来了Underlay无法提供的灵活性。那么Overlay网络又是如何形成的呢? Overlay网络是如何形成的? Overlay是基于软件的,不依赖于传输,它就像物理网络之上的虚拟网络。 Overlay网络的一个典型例子是Internet VPN ,它在Internet上构建了一个虚拟的封闭网络。通过使用IPsec等协议构建虚拟网络,使私有 IP 地址的通信成为可能。此外,SDN和SD-WAN也采用了Overlay网络的概念。 但是,要在 SD-WAN 中构建Overlay,需要一个特殊 CPE,称为 SD-WAN 边缘设备。 💫31 Docker Base - 图58 下面以SD-WAN边缘设备建立GRE隧道为例进行说明。相互连接的SD-WAN边缘设备之间建立隧道,数据包准备传输出去时,设备为数据包添加新的IP头部和隧道头部,并将内部IP头与MPLS域隔离,MPLS转发基于外部IP头进行。 一旦数据包到达其目的地,SD-WAN 边缘设备将删除外部 IP 标头和隧道标头,得到的是原始 IP 数据包。在整个过程中,Overlay网络感知不到Underlay网络。 💫31 Docker Base - 图59 同样的过程也可以用于Internet Underlay,但需要使用IPSec进行加密。 Overlay网络如何解决问题? 1)使用加密技术可以保护私密流量在互联网上的通信。 2)流量传输不依赖特定线路。Overlay网络使用隧道技术,可以灵活选择不同的底层链路,使用多种方式保证流量的稳定传输。 3)支持多路径转发。在Overlay网络中,流量从源传输到目的可通过多条路径,从而实现负载分担,最大化利用线路的带宽。 4)支持网络切片与网络分段。将不同的业务分割开来,可以实现网络资源的最优分配。 Overlay vs Underlay总结 💫31 Docker Base - 图60 ### 4.9.2 Overlay 和 Underlay 网络和 etcd 多机容器通信 💫31 Docker Base - 图61 :::color5 多级容器通信前提需要一个分布式的数据库存储。例如:etcd ::: bash # docker-node1 执行 $ wget https://github.com/coreos/etcd/releases/download/v3.0.12/etcd-v3.0.12-linux-amd64.tar.gz && \ tar -zxvf etcd-v3.0.12-linux-amd64.tar.gz && \ cd etcd-v3.0.12-linux-amd64/ $ nohup ./etcd --name docker-node1 --initial-advertise-peer-urls http://10.0.0.54:2380 \ --listen-peer-urls http://10.0.0.54:2380 \ --listen-client-urls http://10.0.0.54:2379,http://127.0.0.1:2379 \ --advertise-client-urls http://10.0.0.54:2379 \ --initial-cluster-token etcd-cluster \ --initial-cluster docker-node1=http://10.0.0.54:2380,docker-node2=http://10.0.0.55:2380 \ --initial-cluster-state new& # docker-node2 执行 $ wget https://github.com/coreos/etcd/releases/download/v3.0.12/etcd-v3.0.12-linux-amd64.tar.gz && \ tar -zxvf etcd-v3.0.12-linux-amd64.tar.gz && \ cd etcd-v3.0.12-linux-amd64/ $ nohup ./etcd --name docker-node2 --initial-advertise-peer-urls http://10.0.0.55:2380 \ --listen-peer-urls http://10.0.0.55:2380 \ --listen-client-urls http://10.0.0.55:2379,http://127.0.0.1:2379 \ --advertise-client-urls http://10.0.0.55:2379 \ --initial-cluster-token etcd-cluster \ --initial-cluster docker-node1=http://10.0.0.54:2380,docker-node2=http://10.0.0.55:2380 \ --initial-cluster-state new& # 检查cluster状态 $ ./etcdctl cluster-health member 24799c1b49c6e14a is healthy: got healthy result from http://10.0.0.55:2379 member fff59d175897acad is healthy: got healthy result from http://10.0.0.54:2379 cluster is healthy # 重启 Docker 服务 # docker-node1 执行 systemctl stop docker && systemctl status docker sudo /usr/bin/dockerd -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock --cluster-store=etcd://10.0.0.54:2379 --cluster-advertise=10.0.0.54:2375& # 查看Docker Server是否启动 docker version # docker-node2 执行 systemctl stop docker && systemctl status docker sudo /usr/bin/dockerd -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock --cluster-store=etcd://10.0.0.55:2379 --cluster-advertise=10.0.0.55:2375& # 查看Docker Server是否启动 docker version 💫31 Docker Base - 图62 创建 Overlay Network bash # 在 docker-node1 上创建一个 demo 的Overlay Network $ sudo docker network ls $ sudo docker network create -d overlay demo $ sudo docker network ls NETWORK ID NAME DRIVER SCOPE 5343b47f0509 bridge bridge local d9d5a59dde06 demo overlay global fc0af5687697 host host local c1c197f8a9e1 none null local # 在 docker-node2 查看Docker 网络 $ sudo docker network ls NETWORK ID NAME DRIVER SCOPE 6d236fecdb41 bridge bridge local d9d5a59dde06 demo overlay global 8b95bbe9b9ff host host local ee36fdaebca6 none null local $ docker network inspect demo [ { "Name": "demo", "Id": "d9d5a59dde0612b127004fbf9e7b0eb024c18c67bffdadc01fb6535e26c26f58", "Created": "2022-11-06T17:58:53.574544295+08:00", "Scope": "global", "Driver": "overlay", "EnableIPv6": false, "IPAM": { "Driver": "default", "Options": {}, "Config": [ { "Subnet": "10.0.0.0/24", "Gateway": "10.0.0.1" } ] }, "Internal": false, "Attachable": false, "Ingress": false, "ConfigFrom": { "Network": "" }, "ConfigOnly": false, "Containers": {}, "Options": {}, "Labels": {} } ] # 在 docker-node1 创建一个 Container容器 $ docker run -it -d --name test1 --net demo busybox sh -c "while true; do sleep 3600; done" $ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 19ad5d2a1850 busybox "sh -c 'while true; …" 4 seconds ago Up 3 seconds test1 # 查看 test1 容器的IP地址 $ docker exec -it test1 ip addr 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue 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 8: eth0@if9: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1450 qdisc noqueue link/ether 02:42:0a:00:00:02 brd ff:ff:ff:ff:ff:ff inet 10.0.0.2/24 brd 10.0.0.255 scope global eth0 valid_lft forever preferred_lft forever 11: eth1@if12: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue link/ether 02:42:ac:12:00:02 brd ff:ff:ff:ff:ff:ff inet 172.18.0.2/16 brd 172.18.255.255 scope global eth1 valid_lft forever preferred_lft forever # 在 docker-node2 创建一个 Container容器 # docker-node2 无法创建容器名为 test1 的容器 $ docker run -it -d --name test1 --network demo busybox sh -c "while true; do sleep 3600; done" Unable to find image 'busybox:latest' locally latest: Pulling from library/busybox 5cc84ad355aa: Pull complete Digest: sha256:5acba83a746c7608ed544dc1533b87c737a0b0fb730301639a0179f9344b1678 Status: Downloaded newer image for busybox:latest 5f72796a3601588e0414f0e3f57cf924f7c4305d61a06cbc9bb39b5797054cbb ERRO[2022-11-06T18:03:22.036319292+08:00] 5f72796a3601588e0414f0e3f57cf924f7c4305d61a06cbc9bb39b5797054cbb cleanup: failed to delete container from containerd: no such container docker: Error response from daemon: endpoint with name test1 already exists in network demo. # docker-node2 创建容器名为 test2 的容器 $ docker run -it -d --name test2 --network demo busybox sh -c "while true; do sleep 3600; done" # 查看 test2 容器的IP地址 $ docker exec test2 ip addr 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue 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 8: eth0@if9: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1450 qdisc noqueue link/ether 02:42:0a:00:00:03 brd ff:ff:ff:ff:ff:ff inet 10.0.0.3/24 brd 10.0.0.255 scope global eth0 valid_lft forever preferred_lft forever 11: eth1@if12: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue link/ether 02:42:ac:12:00:02 brd ff:ff:ff:ff:ff:ff inet 172.18.0.2/16 brd 172.18.255.255 scope global eth1 valid_lft forever preferred_lft forever ### 4.9.3 发现docker_gwbridge的网络模式 bash $ docker network ls NETWORK ID NAME DRIVER SCOPE 5343b47f0509 bridge bridge local d9d5a59dde06 demo overlay global 9dadab18bc62 docker_gwbridge bridge local fc0af5687697 host host local c1c197f8a9e1 none null local 在容器内部创建了两个接口,这两个接口对应于主机上现在存在的两个网桥。在覆盖网络上,每个容器至少有两个接口将它连接到 <font style="color:rgb(199, 37, 78);background-color:rgb(242, 242, 242);">overlay</font><font style="color:rgb(64, 64, 64);"></font><font style="color:rgb(199, 37, 78);background-color:rgb(242, 242, 242);">docker_gwbridge</font>

💫31 Docker Base - 图63

网桥 目的
overlay 入口和出口指向VXLAN封装的覆盖网络,并(可选)加密同一覆盖网络上的容器之间的流量。它将覆盖范围扩展到参与此特定叠加层的所有主机。一个主机上的每个覆盖子网将存在一个,并且它将具有与给定特定覆盖网络相同的名称。
docker_gwbridge 离开集群的流量的出口桥。docker_gwbridge 每个主机只能存在一个。此网桥上的容器到容器之间流量被阻止,仅允许入口/出口流量。

:::color5 数据最初从容器的 eth1ovnet, 在此,进行 VXLAN 的封装,经过封装后的数据帧最终由 docker_gwbridge网络 路由 到宿主机的网络上,再有宿主机的网络继续正确的数据路由转发。

:::

范例:将 Overlay Network的两个容器相互ping通

  1. # docker-node1 执行ping通 docker-node2
  2. $ docker exec -it test1 ping -c1 -W1 10.0.0.3
  3. PING 10.0.0.3 (10.0.0.3): 56 data bytes
  4. 64 bytes from 10.0.0.3: seq=0 ttl=64 time=0.870 ms
  5. --- 10.0.0.3 ping statistics ---
  6. 1 packets transmitted, 1 packets received, 0% packet loss
  7. round-trip min/avg/max = 0.870/0.870/0.870 ms
  8. $ docker exec -it test1 ping -c1 -W1 test2
  9. PING test2 (10.0.0.3): 56 data bytes
  10. 64 bytes from 10.0.0.3: seq=0 ttl=64 time=0.678 ms
  11. --- test2 ping statistics ---
  12. 1 packets transmitted, 1 packets received, 0% packet loss
  13. round-trip min/avg/max = 0.678/0.678/0.678 ms
  14. # docker-node2 执行ping通 docker-node1
  15. $ docker exec -it test2 ping -c1 -W1 10.0.0.2
  16. PING 10.0.0.2 (10.0.0.2): 56 data bytes
  17. 64 bytes from 10.0.0.2: seq=0 ttl=64 time=0.653 ms
  18. --- 10.0.0.2 ping statistics ---
  19. 1 packets transmitted, 1 packets received, 0% packet loss
  20. round-trip min/avg/max = 0.653/0.653/0.653 ms
  21. $ docker exec -it test2 ping -c1 -W1 test1
  22. PING test1 (10.0.0.2): 56 data bytes
  23. 64 bytes from 10.0.0.2: seq=0 ttl=64 time=0.543 ms
  24. --- test1 ping statistics ---
  25. 1 packets transmitted, 1 packets received, 0% packet loss
  26. round-trip min/avg/max = 0.543/0.543/0.543 ms

这就实现不同的机器的不同容器的IP地址的通信。

💫31 Docker Base - 图64

  1. # 在Docker node1运行 redis
  2. $ docker run -it -d --name redis --network demo redis
  3. $ docker ps
  4. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  5. 189a9f8a2978 redis "docker-entrypoint.s…" 4 seconds ago Up 2 seconds 6379/tcp redis
  6. # 在Docker node2运行 flask-redis
  7. $ vim app.py
  8. import os
  9. import socket
  10. from flask import Flask
  11. from redis.client import Redis
  12. app = Flask(__name__)
  13. redis = Redis(host=os.environ.get('REDIS_HOST', '127.0.0.1'), port=6379)
  14. @app.route('/')
  15. def hello():
  16. redis.incr('hits')
  17. return 'Hello Container World! I have been seen %s times and my hostname is %s.\n' % (
  18. redis.get('hits'), socket.gethostname())
  19. if __name__ == "__main__":
  20. app.run(host="0.0.0.0", port=5000, debug=True)
  21. $ vim Dockerfile
  22. FROM python:2.7
  23. LABEL maintainer="zhongzhiwei <zhongzhiwei@kubesphere.io>"
  24. RUN mkdir -p /app && \
  25. pip install flask redis
  26. WORKDIR /app
  27. COPY . /app
  28. EXPOSE 5000
  29. CMD [ "python", "app.py" ]
  30. $ docker build -t flask-redis:v1.0 -f Dockerfile .
  31. ################################################################################################################################
  32. $ docker run -it -d --name flask-redis -p 5000:5000 -e REDIS_HOST=redis --network demo flask-redis:v1.0
  33. $ docker exec -it flask-redis /bin/bash
  34. root@da02b8e1a821:/app# curl 127.0.0.1:5000
  35. Hello Container World! I have been seen 1 times and my hostname is da02b8e1a821.
  36. root@da02b8e1a821:/app# curl 127.0.0.1:5000
  37. Hello Container World! I have been seen 2 times and my hostname is da02b8e1a821.
  38. # 通过宿主机访问
  39. $ curl 127.0.0.1:5000
  40. Hello Container World! I have been seen 3 times and my hostname is da02b8e1a821.
  41. $ curl 127.0.0.1:5000
  42. Hello Container World! I have been seen 4 times and my hostname is da02b8e1a821.

5 Docker 的持久化存储和数据共享

5.1 Container Layer

💫31 Docker Base - 图65

Container 是 Image 之上创建的,是一个运行时环境。在Container Layer 是可以写入数据的。

管理员创建一个Container容器,写入的数据均在Container中,在没有做数据持久化的前提下,如果删除了该Container,那么之前在Container内的数据就会全部丢失。所以Container是临时存储保存数据的。例如:数据库的容器存储是必须要进行数据持久化的。所以Docker 就引用了数据持久化的机制。

5.2 Data Volume

5.2.1 Docker 容器数据卷是什么

:::color1 数据卷就是目录或者文件,存在于一个或者多个容器中,由Docker挂载到容器,但是不属于联合文件系统,因此能够绕过 Union File System 提供一些用于持续存储或者共享数据的特性:

卷的设计目的就是数据持久化,完全独立于容器的生存周期,因此Docker不会在容器删除时删除其挂载的数据卷。

Docker 容器(数据) →容器数据卷方式完成数据的持久化重要资料backup→ 映射,容器内的数据备份+持久化到本地主机目录

:::

一句话:类似于Redis的RDB文件和AOF文件

将Docker容器内的数据保存进宿主机的磁盘中

运行一个带有容器卷存储功能的容器实例

  1. $ docker run -it --privileged=true -v /宿主机绝对路径:/容器内目录 镜像名

💫31 Docker Base - 图66

5.2.2 Docker 容器数据卷能干嘛

  • 将运用与运行的环境打包镜像,run 后形成容器实例运行,但是我们对数据的要求希望是持久化的
  • Docker 容器产生的数据,如果不备份,那么当容器实例删除后,容器内的数据自然也就没有了
  • 为了能保存数据在Docker中我们使用数据卷
  • 特点:
    • 数据据可以在容器之间共享或者重用数据
    • 卷中的更改可以直接实时生效(跟 docker cp 比较)
    • 数据卷中的更改不会包含在镜像的更新中
    • 数据卷的生命周期一直持续到没有容器使用它为止

5.3 Docker 持久化数据的方案

  • 基于本地文件系统的Volume。可以在执行Docker create或Docker run时,通过-v参数将主机的目录作为容器的数据卷。这部分功能便是基于本地文件系统的volume管理。
  • 基于plugin的Volume,支持第三方的存储方案,比如NAS ,AWS。

5.4 Volume 的类型

  • 受管理的data Volume,由Docker后台自动创建。
  • 绑定挂载的Volume,具体挂载位置可以由用户指定。

5.5 数据持久化:Data Volume

💫31 Docker Base - 图67

MySQL Dockerfile GitHub:

Reference:https://github.com/docker-library/mysql/blob/e0d43b2a29867c5b7d5c01a8fea30a086861df2b/8.0/Dockerfile.oracle

💫31 Docker Base - 图68

范例:创建MySQL容器

  1. $ docker run -it -d --name mysql1 -e MYSQL_ROOT_PASSWORD="Admin@h3c" mysql:5.7.40
  2. $ docker ps
  3. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  4. 2a0ff6fb860b mysql:5.7.40 "docker-entrypoint.s…" 9 seconds ago Up 8 seconds 3306/tcp, 33060/tcp mysql1
  5. # 1. 匿名卷
  6. # 查看 Docker 数据卷的信息
  7. $ docker volume ls
  8. DRIVER VOLUME NAME
  9. local 8174f8c54b9fb877b5d5cf93893927fe4445a8be2b1aa31bb6393eea579d2e32
  10. $ docker volume inspect 8174f8c54b9fb877b5d5cf93893927fe4445a8be2b1aa31bb6393eea579d2e32
  11. [
  12. {
  13. "CreatedAt": "2022-11-06T20:13:36+08:00",
  14. "Driver": "local",
  15. "Labels": null,
  16. "Mountpoint": "/var/lib/docker/volumes/8174f8c54b9fb877b5d5cf93893927fe4445a8be2b1aa31bb6393eea579d2e32/_data",
  17. "Name": "8174f8c54b9fb877b5d5cf93893927fe4445a8be2b1aa31bb6393eea579d2e32",
  18. "Options": null,
  19. "Scope": "local"
  20. }
  21. ]
  22. # 删除容器,并查看数据卷是否存在
  23. $ docker rm -f mysql1
  24. $ docker volume ls
  25. DRIVER VOLUME NAME
  26. local 8174f8c54b9fb877b5d5cf93893927fe4445a8be2b1aa31bb6393eea579d2e32
  27. # 2. 具名卷
  28. # 但是发现其VOLUME NAME数据卷名称并不友好(指定数据卷名)
  29. $ docker run -it -d --name mysql1 -e MYSQL_ROOT_PASSWORD="Admin@h3c" -v mysqlvolume:/var/lib/mysql mysql:5.7.40
  30. $ docker volume ls
  31. DRIVER VOLUME NAME
  32. local mysqlvolume
  33. $ docker volume inspect mysqlvolume
  34. [
  35. {
  36. "CreatedAt": "2022-11-06T20:16:34+08:00",
  37. "Driver": "local",
  38. "Labels": null,
  39. "Mountpoint": "/var/lib/docker/volumes/mysqlvolume/_data",
  40. "Name": "mysqlvolume",
  41. "Options": null,
  42. "Scope": "local"
  43. }
  44. ]
  45. # 验证数据卷是否生效
  46. $ docker exec -it mysql1 /bin/bash
  47. bash-4.2# mysql -uroot -pAdmin@h3c
  48. mysql: [Warning] Using a password on the command line interface can be insecure.
  49. Welcome to the MySQL monitor. Commands end with ; or \g.
  50. Your MySQL connection id is 2
  51. Server version: 5.7.40 MySQL Community Server (GPL)
  52. Copyright (c) 2000, 2022, Oracle and/or its affiliates.
  53. Oracle is a registered trademark of Oracle Corporation and/or its
  54. affiliates. Other names may be trademarks of their respective
  55. owners.
  56. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
  57. mysql> show databases;
  58. +--------------------+
  59. | Database |
  60. +--------------------+
  61. | information_schema |
  62. | mysql |
  63. | performance_schema |
  64. | sys |
  65. +--------------------+
  66. 4 rows in set (0.00 sec)
  67. mysql> create database docker;
  68. Query OK, 1 row affected (0.00 sec)
  69. mysql> exit
  70. Bye
  71. bash-4.2# exit
  72. # 删除 mysql1 的容器
  73. $ sudo docker rm -f mysql1
  74. # 启用另一个 mysql2 容器使用 mysql1 的数据卷
  75. $ docker volume ls
  76. DRIVER VOLUME NAME
  77. local mysqlvolume
  78. $ docker run -it -d --name mysql2 -e MYSQL_ROOT_PASSWORD="Admin@h3c" -v mysqlvolume:/var/lib/mysql mysql:5.7.40
  79. $ docker exec -it mysql2 /bin/bash
  80. bash-4.2# mysql -uroot -pAdmin@h3c
  81. mysql: [Warning] Using a password on the command line interface can be insecure.
  82. Welcome to the MySQL monitor. Commands end with ; or \g.
  83. Your MySQL connection id is 2
  84. Server version: 5.7.40 MySQL Community Server (GPL)
  85. Copyright (c) 2000, 2022, Oracle and/or its affiliates.
  86. Oracle is a registered trademark of Oracle Corporation and/or its
  87. affiliates. Other names may be trademarks of their respective
  88. owners.
  89. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
  90. mysql> show databases;
  91. +--------------------+
  92. | Database |
  93. +--------------------+
  94. | information_schema |
  95. | docker |
  96. | mysql |
  97. | performance_schema |
  98. | sys |
  99. +--------------------+
  100. 5 rows in set (0.00 sec)

5.6 数据持久化:Bind Mouting

5.6.1 简单使用 Bind Mouting

💫31 Docker Base - 图69

  1. $ mkdir -pv /root/dockerfile/docker-nginx && cd /root/dockerfile/docker-nginx
  2. $ vim Dockerfile
  3. # 指定基础镜像
  4. FROM nginx:latest AS baseimg
  5. # 指定工作目录
  6. WORKDIR /usr/share/nginx/html
  7. # 拷贝页面文件到容器内
  8. COPY index.html index.html
  9. $ cat > index.html <<-'EOF'
  10. <h1>This is the Docker Page!</h1>
  11. <h2>Hello Docker!</h2>
  12. EOF
  13. # 构建成一个镜像
  14. $ docker build -t my-nginx:v1.0 -f Dockerfile .
  15. # 运行成一个容器
  16. $ docker run -it -p 10880:80 -d --name web01 my-nginx:v1.0
  17. $ curl 127.0.0.1:10880
  18. <h1>This is the Docker Page!</h1>
  19. <h2>Hello Docker!</h2>

💫31 Docker Base - 图70

  1. $ docker rm -f web01
  2. # 使用指定宿主机路径进行挂载到容器内
  3. $ docker run -it -p 10880:80 -d \
  4. -v /root/dockerfile/docker-nginx:/usr/share/nginx/html --name web01 my-nginx:v1.0
  5. # 容器操作
  6. $ docker exec -it web01 /bin/bash
  7. root@7cceb0798a3d:/usr/share/nginx/html# pwd
  8. /usr/share/nginx/html
  9. root@7cceb0798a3d:/usr/share/nginx/html# ls
  10. Dockerfile index.html
  11. root@7cceb0798a3d:/usr/share/nginx/html# echo "Docker Content" > docker.txt
  12. root@7cceb0798a3d:/usr/share/nginx/html# exit
  13. # 宿主机操作
  14. $ cd /root/dockerfile/docker-nginx
  15. $ ls -l
  16. total 12
  17. -rw-r--r-- 1 root root 163 Nov 6 20:29 Dockerfile
  18. -rw-r--r-- 1 root root 15 Nov 6 20:36 docker.txt
  19. -rw-r--r-- 1 root root 57 Nov 6 20:30 index.html
  20. $ cat docker.txt
  21. Docker Content
  22. $ echo "Host Content" >> docker.txt
  23. # 容器查看是否有内容同步到
  24. $ docker exec -it web01 cat docker.txt
  25. Docker Content
  26. Host Content

5.6.2 Bind Mouting 实际项目

Video Reference:https://www.bilibili.com/video/BV1xe4y1q7fC?p=41

5.7 将所学知识部署 WordPress 页面

创建自定义网络以及下载镜像

  1. # 创建相应的自定义网络
  2. docker network create --driver bridge wordpress_net
  3. # 下载相应的镜像
  4. docker pull mariadb:10.6.4-focal
  5. docker pull wordpress

部署 MySQL / MariaDB

  1. # 不需要暴露宿主机的3306端口
  2. docker run -it -d --name db -v db_data:/var/lib/mysql \
  3. --restart=always -e MYSQL_ROOT_PASSWORD=somewordpress \
  4. -e MYSQL_DATABASE=wordpress -e MYSQL_USER=wordpress \
  5. --network wordpress_net \
  6. -e MYSQL_PASSWORD=wordpress mariadb:10.6.4-focal --default-authentication-plugin=mysql_native_password

部署 WordPress 页面

  1. docker run -it -d --name wordpress --restart=always \
  2. -e WORDPRESS_DB_HOST=db -e WORDPRESS_DB_USER=wordpress \
  3. --network wordpress_net \
  4. -e WORDPRESS_DB_PASSWORD=wordpress -e WORDPRESS_DB_NAME=wordpress \
  5. -p 80:80 wordpress

访问 WordPress 页面

  1. http://110.41.20.249/
http://:80 后续的操作就是 WordPress 根据引导进行部署即可

💫31 Docker Base - 图71

💫31 Docker Base - 图72

💫31 Docker Base - 图73

这样 博客就搭建完成了!

6 Docker Compose

6.1 Docker Compose 是什么

Docker Compose是一个用来定义和运行复杂应用的Docker工具。一个使用Docker容器的应用,通常由多个容器组成。使用Docker Compose不再需要使用shell脚本来启动容器。 Compose 通过一个配置文件来管理多个Docker容器,在配置文件中,所有的容器通过services来定义,然后使用docker-compose脚本来启动,停止和重启应用,和应用中的服务以及所有依赖服务的容器,非常适合组合使用多个容器进行开发的场景。 Docker-compose 是 Docker 官方的开源项目,负责实现对 Docker 容器集群的快速编排 Docker-compose 是 Docker 公司推出的一个工具软件,可以管理多个 Docker 容器组成一个应用。需要定义一个YAML格式的配置文件 docker-compose.yml写好多个容器之间的调用关系。然后,只要一个命令,就能同时启动/关闭这些容器。

:::color1

docker-compose 还是非常爽的,用了以后,完全不像用 docker 启动容器 最简单的理解就是把多个docker容器的启动命令写在一个脚本里,批量启动容器(写好多个容器之间的命令关系) Docker Compose来轻松高效的管理容器。定义运行多个容器。

:::

画板

官方文档介绍 Compose是一个用于定义和运行多容器Docker应用程序的工具。使用Compose,您可以使用一个YAML文件来配置应用程序的服务。然后,使用一个命令创建并启动配置中的所有服务。要了解Compose的所有特性的更多信息,请参阅特性列表。 在所有环境中编写工作:生产、开发、测试以及CI工作流。您可以在常用用例中了解更多关于每个用例的信息。 使用Compose基本上有三个步骤:
  1. Dockerfile 定义你的应用环境,这样它就可以在任何地方被复制。
  2. docker-compose.yml 中定义组成应用程序的服务。所以它们可以在一个孤立的环境中一起运行。
  3. 运行docker compose up , docker compose up命令将启动并运行整个应用程序。你也可以使用compose standalone(docker-compose binary)运行docker-compose。
作用:批量容器编排。
Compose 是 Docker 官方的开源项目,需要独立安装! Dockerfile 让程序在任何地方运行。Docker Compose 是单个机器的容器编排工具。

:::color2 多容器的 APP 太恶心

:::

  • 要从Dockerfile build image或者Dockerhub拉取image
  • 要创建多个container
  • 要管理这些container(启动停止删除)

:::color2 Docker Compose “批处理”

:::

💫31 Docker Base - 图75

:::color2 Docker Compose

:::

  • Docker Compose 是一个工具
  • 这个工具可以通过一个 yml 文件定义多容器的 Docker应用
  • 通过一条命令就可以根据 yml 文件的定义去创建或者管理这多个容器

:::color2 docker-compose.yml

:::

💫31 Docker Base - 图76

:::color2 Services

:::

  • 一个 Service 就代表一个 Container,这个Container 可以从 DockerHub 的 Image 来创建,或者从本地的 Dockerfile build 出来的 image 来创建。
  • Service 的启动类似 docker run,我们可以给其指定 Network 和 Volume,所以可以给 service 指定 Network 和 Volume 的引用。

💫31 Docker Base - 图77

  • 使用 Dockerfile 创建容器(docker build)

💫31 Docker Base - 图78

:::color2 Volumes

:::

💫31 Docker Base - 图79

:::color2 Networks

:::

💫31 Docker Base - 图80

:::color2 Docker Compose v2 和 v3 版本的区别

:::

  • 由于 Swarm mode 中网络的特殊性,Compose v3版本配置文件中一些声明比如<font style="color:rgb(232, 62, 140);background-color:rgb(246, 246, 246);">expose</font><font style="color:rgb(232, 62, 140);background-color:rgb(246, 246, 246);">links</font>会被忽略。注意:不能再使用 link 定义的网络别名来进行容器互联,可以使用服务名连接。
  • Compose v3版本配置文件中<font style="color:rgb(232, 62, 140);background-color:rgb(246, 246, 246);">volumes_from</font>不再支持,只能使用命名数据卷来实现容器数据的持久化和共享。
  • Compose v3版本配置文件中引入了<font style="color:rgb(232, 62, 140);background-color:rgb(246, 246, 246);">deploy</font>指令,可对Swarm mode中服务部署的进行细粒度控制,包括 - <font style="color:rgb(232, 62, 140);background-color:rgb(246, 246, 246);">resources</font>:定义<font style="color:rgb(232, 62, 140);background-color:rgb(246, 246, 246);">cpu_shares</font>,<font style="color:rgb(232, 62, 140);background-color:rgb(246, 246, 246);">cpu_quota</font>,<font style="color:rgb(232, 62, 140);background-color:rgb(246, 246, 246);">cpuset</font>,<font style="color:rgb(232, 62, 140);background-color:rgb(246, 246, 246);">mem_limit</font>,<font style="color:rgb(232, 62, 140);background-color:rgb(246, 246, 246);">memswap_limit</font>等容器资源限制指令。(v1/v2中相应指令在v3版本的配置文件中不再被支持)- <font style="color:rgb(232, 62, 140);background-color:rgb(246, 246, 246);">restart_policy</font>:定义服务的重启条件 (v1/v2中<font style="color:rgb(232, 62, 140);background-color:rgb(246, 246, 246);">restart</font>指令在v3版本的配置文件中不再被支持)

6.2 Docker Compose 安装和基本使用

  1. # 下载可执行文件docker-compose
  2. curl -L https://get.daocloud.io/docker/compose/releases/download/v2.12.2/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
  3. # 将文件添加执行权限
  4. chmod +x /usr/local/bin/docker-compose
  5. # 验证docker-compose版本
  6. $ docker-compose version
  7. Docker Compose version v2.12.2

6.2.1 Docker-Compose 的相关命令

:::color2 Compose 常用命令

  • docker-compose -h —-> 查看帮助
  • docker-compose up —-> 启动所有docker-compose服务
  • docker-compose up -d ---> 启动服务 docker-compose 服务,并后台运行
  • docker-compose down ---> 停止并删除容器、网络、卷、镜像
  • docker-compose exec yml里面的服务id —-> 进入容器实例内部 [ docker-compose exec docker-compose.yml文件中写的服务id /bin/bash ]
  • docker-compose ps —-> 展示当前 docker-compose 编排过的运行的所有容器
  • docker-compose top —-> 展示当前 docker-compose 编排过的容器进程
  • docker-compose logs yml里面的服务id —-> 检查容器输出日志
  • docker-compose config ---> 检查配置
  • docker-compose config -q ---> 检查配置,有问题才有输出
  • docker-compose restart —-> 重启服务
  • docker-compose start —-> 启动服务
  • docker-compose stop —-> 停止服务
  • docker-compose images —-> 查看 docker-compose 使用的镜像
  • docker-compose build —-> 会构建 docker-compose 中的所有 Dockerfile 的构建镜像

:::

6.3 使用 Compose 一键部署 WordPress 博客

:::color1

传统方式部署博客:
  • 下载程序,安装数据库,配置……
  • compose 应用 → 一键启动
1、下载项目( docker-compose.yml ) 2、如果需要文件。Dockerfile 3、文件准备齐全(直接 docker-compose up 一键启动项目!)

:::

官方文档:https://docs.docker.com/samples/wordpress/

  1. #创建一个项目的文件夹(这就是项目名project)
  2. $ mkdir /opt/my_wordpress ; cd /opt/my_wordpress
  3. $ vim docker-compose.yml
  4. version: "3.9"
  5. services:
  6. db:
  7. # We use a mariadb image which supports both amd64 & arm64 architecture
  8. image: mariadb:10.6.4-focal
  9. # If you really want to use MySQL, uncomment the following line
  10. #image: mysql:8.0.27
  11. command: '--default-authentication-plugin=mysql_native_password'
  12. volumes:
  13. - db_data:/var/lib/mysql
  14. restart: always
  15. environment:
  16. - MYSQL_ROOT_PASSWORD=somewordpress
  17. - MYSQL_DATABASE=wordpress
  18. - MYSQL_USER=wordpress
  19. - MYSQL_PASSWORD=wordpress
  20. expose:
  21. - 3306
  22. - 33060
  23. wordpress:
  24. image: wordpress:latest
  25. ports:
  26. - 80:80
  27. restart: always
  28. environment:
  29. - WORDPRESS_DB_HOST=db
  30. - WORDPRESS_DB_USER=wordpress
  31. - WORDPRESS_DB_PASSWORD=wordpress
  32. - WORDPRESS_DB_NAME=wordpress
  33. volumes:
  34. db_data:
  35. #启动项目
  36. #-d 后台运行
  37. #不加 -d 就是默认前台启动
  38. $ docker-compose -f docker-compose.yml up -d
  39. $ docker ps
  40. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  41. 70d3fc3fbb45 wordpress:latest "docker-entrypoint.s…" About a minute ago Up About a minute 0.0.0.0:80->80/tcp, :::80->80/tcp my_wordpress-wordpress-1
  42. 459eccc745ed mariadb:10.6.4-focal "docker-entrypoint.s…" About a minute ago Up About a minute 3306/tcp, 33060/tcp my_wordpress-db-1
  43. $ docker port my_wordpress-wordpress-1
  44. 80/tcp -> 0.0.0.0:80
  45. 80/tcp -> :::80

💫31 Docker Base - 图81

http://:80 后续的操作就是 WordPress 根据引导进行部署即可

💫31 Docker Base - 图82

💫31 Docker Base - 图83

💫31 Docker Base - 图84

这样 博客就搭建完成了

:::color1

目前的IT主流的技术:Linux + Docker + Kubernetes(掌握) 掌握的技术:Docker 基础、原理、网络、服务、集群、错误排查、日志

:::

6.4 Flask-Redis 使用 docker-compose 文件启动

  1. version: "3"
  2. services:
  3. redis:
  4. image: redis
  5. web:
  6. build:
  7. context: .
  8. dockerfile: Dockerfile
  9. ports:
  10. - 8080:5000
  11. environment:
  12. REDIS_HOST: redis

文件列表目录:

💫31 Docker Base - 图85

  1. $ vim app.py
  2. import os
  3. import socket
  4. from flask import Flask
  5. from redis.client import Redis
  6. app = Flask(__name__)
  7. redis = Redis(host=os.environ.get('REDIS_HOST', '127.0.0.1'), port=6379)
  8. @app.route('/')
  9. def hello():
  10. redis.incr('hits')
  11. return 'Hello Container World! I have been seen %s times and my hostname is %s.\n' % (
  12. redis.get('hits'), socket.gethostname())
  13. if __name__ == "__main__":
  14. app.run(host="0.0.0.0", port=5000, debug=True)
  1. $ vim Dockerfile
  2. FROM python:2.7
  3. LABEL maintainer="zhongzhiwei <zhongzhiwei@kubesphere.io>"
  4. RUN mkdir -p /app && \
  5. pip install flask redis
  6. WORKDIR /app
  7. COPY . /app
  8. EXPOSE 5000
  9. CMD [ "python", "app.py" ]

使用 docker-compose 启动

  1. docker-compose up -d

💫31 Docker Base - 图86

  1. $ docker-compose ps
  2. NAME COMMAND SERVICE STATUS PORTS
  3. flask-redis-redis-1 "docker-entrypoint.s…" redis running 6379/tcp
  4. flask-redis-web-1 "python app.py" web running 0.0.0.0:8080->5000/tcp, :::8080->5000/tcp
  5. # 验证是否成功
  6. $ curl localhost:8080
  7. Hello Container World! I have been seen 1 times and my hostname is d6e9f1006ae6.

范例:使用浏览器访问

💫31 Docker Base - 图87

6.5 水平扩展和负载均衡

6.5.1 水平扩展

水平扩展,是指通过增加更多的服务器或者程序实例来分散负载,从而提升存储能力和计算能力。

实现水平扩展(在 6.4 Flask-Redis 使用 docker-compose 文件启动 基础上进行修改)

💫31 Docker Base - 图88

  1. # 修改配置文件,将宿主机端口8080映射删除
  2. $ vim docker-compose.yaml
  3. version: "3"
  4. services:
  5. redis:
  6. image: redis
  7. web:
  8. build:
  9. context: .
  10. dockerfile: Dockerfile
  11. environment:
  12. REDIS_HOST: redis
  1. # 中止docker-compose运行的容器
  2. $ docker-compose down
  3. # 水平扩展
  4. $ docker-compose up --scale web=3 -d
  5. [+] Running 5/5
  6. Network flask-redis_default Created 0.1s
  7. Container flask-redis-web-3 Started 1.5s
  8. Container flask-redis-redis-1 Started 0.9s
  9. Container flask-redis-web-1 Started 1.5s
  10. Container flask-redis-web-2 Started 0.9s
  11. $ docker-compose ps
  12. NAME COMMAND SERVICE STATUS PORTS
  13. flask-redis-redis-1 "docker-entrypoint.s…" redis running 6379/tcp
  14. flask-redis-web-1 "python app.py" web running 5000/tcp
  15. flask-redis-web-2 "python app.py" web running 5000/tcp
  16. flask-redis-web-3 "python app.py" web running 5000/tcp

💫31 Docker Base - 图89

💫31 Docker Base - 图90

6.5.2 负载均衡

负载均衡建立在现有网络结构之上,它提供了一种廉价有效透明的方法扩展网络设备服务器的带宽、增加吞吐量、加强网络数据处理能力、提高网络的灵活性和可用性。 负载均衡(Load Balance)其意思就是分摊到多个操作单元上进行执行,例如Web服务器FTP服务器企业关键应用服务器和其它关键任务服务器等,从而共同完成工作任务。
  1. mkdir -pv lb-scale ; cd lb-scale
  2. cat > docker-compose.yml <<-'EOF'
  3. version: "3"
  4. services:
  5. redis:
  6. image: redis
  7. restart: always
  8. web01:
  9. build:
  10. context: .
  11. dockerfile: Dockerfile
  12. expose:
  13. - "80"
  14. environment:
  15. REDIS_HOST: redis
  16. restart: always
  17. web02:
  18. build:
  19. context: .
  20. dockerfile: Dockerfile
  21. expose:
  22. - "80"
  23. environment:
  24. REDIS_HOST: redis
  25. restart: always
  26. lb:
  27. image: haproxy
  28. links:
  29. - web01
  30. - web02
  31. ports:
  32. - "7777:1080"
  33. - "8080:8080"
  34. volumes:
  35. - /var/run/docker.sock:/var/run/docker.sock
  36. - ./haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg
  37. restart: always
  38. EOF
  39. # 设置 HAProxy 配置文件
  40. cat > haproxy.cfg <<-'EOF'
  41. #---------------------------------------------------------------------
  42. # Example configuration for a possible web application. See the
  43. # full configuration options online.
  44. #
  45. # http://haproxy.1wt.eu/download/1.4/doc/configuration.txt
  46. #
  47. #---------------------------------------------------------------------
  48. #---------------------------------------------------------------------
  49. # Global settings
  50. #---------------------------------------------------------------------
  51. global #全局配置文件
  52. # to have these messages end up in /var/log/haproxy.log you will
  53. # need to: #配置日志
  54. #
  55. # 1) configure syslog to accept network log events. This is done
  56. # by adding the '-r' option to the SYSLOGD_OPTIONS in
  57. # /etc/sysconfig/syslog #修改syslog配置文件
  58. #
  59. # 2) configure local2 events to go to the /var/log/haproxy.log
  60. # file. A line like the following can be added to
  61. # /etc/sysconfig/syslog #定义日志设备
  62. #
  63. # local2.* /var/log/haproxy.log
  64. #
  65. #log 127.0.0.1 local2 #日志配置,所有的日志都记录本地,通过local2输出
  66. #chroot /var/lib/haproxy #改变haproxy的工作目录
  67. #pidfile /var/run/haproxy.pid #指定pid文件的路径
  68. maxconn 4000 #最大连接数的设定
  69. #user haproxy #指定运行服务的用户
  70. #group haproxy #指定运行服务的用户组
  71. daemon
  72. # turn on stats unix socket
  73. #stats socket /var/lib/haproxy/stats
  74. #---------------------------------------------------------------------
  75. # common defaults that all the 'listen' and 'backend' sections will
  76. # use if not designated in their block
  77. #---------------------------------------------------------------------
  78. defaults
  79. mode http #默认使用协议,可以为{http|tcp|health} http:是七层协议 tcp:是四层 health:只返回OK
  80. log global #全局日志记录
  81. option httplog #详细记录http日志
  82. option dontlognull #不记录空日志
  83. option http-server-close #启用http-server-close
  84. option forwardfor except 127.0.0.0/8 #来自这些信息的都不forwardfor
  85. option redispatch #重新分发,ServerID对应的服务器宕机后,强制定向到其他运行正常的服务器
  86. retries 3 #3次连接失败则认为服务不可用
  87. timeout http-request 10s #默认http请求超时时间
  88. timeout queue 1m #默认队列超时时间
  89. timeout connect 10s #默认连接超时时间
  90. timeout client 1m #默认客户端超时时间
  91. timeout server 1m #默认服务器超时时间
  92. timeout http-keep-alive 10s #默认持久连接超时时间
  93. timeout check 10s #默认检查时间间隔
  94. maxconn 3000 #最大连接数
  95. #---------------------------------------------------------------------
  96. # main frontend which proxys to the backends
  97. #---------------------------------------------------------------------
  98. # frontend main *:80
  99. # #定义ACL规则以如".html"结尾的文件;-i:忽略大小写
  100. # acl url_static path_beg -i /static /images /javascript /stylesheets
  101. # acl url_static path_end -i .jpg .gif .png .css .js
  102. # use_backend static if url_static #调用后端服务器并检查ACL规则是否被匹配
  103. # default_backend app #客户端访问时默认调用后端服务器地址池
  104. #---------------------------------------------------------------------
  105. # static backend for serving up images, stylesheets and such
  106. #---------------------------------------------------------------------
  107. # backend static #定义后端服务器
  108. # balance roundrobin #定义算法;基于权重进行轮询
  109. # server static 127.0.0.1:4331 check check #启动对后端server的健康状态检测
  110. listen stats
  111. bind 0.0.0.0:1080
  112. mode http
  113. stats enable
  114. stats hide-version
  115. stats uri /stats
  116. stats auth admin:admin
  117. #---------------------------------------------------------------------
  118. # round robin balancing between the various backends
  119. #---------------------------------------------------------------------
  120. frontend balance
  121. bind 0.0.0.0:8080
  122. default_backend web_backends
  123. backend web_backends
  124. mode http
  125. option forwardfor
  126. balance roundrobin
  127. server web01 web01:80 check
  128. server web02 web02:80 check
  129. EOF

查看文件列表目录

💫31 Docker Base - 图91

  1. $ vim app.py
  2. import os
  3. import socket
  4. from flask import Flask
  5. from redis.client import Redis
  6. app = Flask(__name__)
  7. redis = Redis(host=os.environ.get('REDIS_HOST', '127.0.0.1'), port=6379)
  8. @app.route('/')
  9. def hello():
  10. redis.incr('hits')
  11. return 'Hello Container World! I have been seen %s times and my hostname is %s.\n' % (
  12. redis.get('hits'), socket.gethostname())
  13. if __name__ == "__main__":
  14. app.run(host="0.0.0.0", port=80, debug=True)
  1. cat > Dockerfile <<-'EOF'
  2. FROM python:2.7
  3. LABEL maintainer="zhongzhiwei <zhongzhiwei@kubesphere.io>"
  4. RUN mkdir -p /app && \
  5. pip install flask redis
  6. WORKDIR /app
  7. COPY . /app
  8. EXPOSE 80
  9. CMD [ "python", "app.py" ]
  10. EOF
  1. $ docker-compose up -d
  2. $ docker-compose ps
  3. NAME COMMAND SERVICE STATUS PORTS
  4. lb-scale-lb-1 "docker-entrypoint.s…" lb running 0.0.0.0:8080->8080/tcp, :::8080->8080/tcp, 0.0.0.0:7777->1080/tcp, :::7777->1080/tcp
  5. lb-scale-redis-1 "docker-entrypoint.s…" redis running 6379/tcp
  6. lb-scale-web01-1 "python app.py" web01 running 80/tcp
  7. lb-scale-web02-1 "python app.py" web02 running 80/tcp

💫31 Docker Base - 图92

测试负载均衡的效果!!!

  1. $ curl localhost:8080

💫31 Docker Base - 图93

查看HAProxy WebUI

  1. # 格式:http://\<IP地址\>:7777/stats
  2. http://10.0.0.54:7777/stats

💫31 Docker Base - 图94

:::color5 可以结合水平扩展和负载均衡合并实验效果!!!

:::

6.6 部署一个复杂的投票应用

💫31 Docker Base - 图95

  1. # GitHub Reference:
  2. # https://github.com/dockersamples/example-voting-app
  3. # Download Reference:
  4. # https://dl-download.csdn.net/down11/20220122/cfdb56694c4b0eda57c1371873fbe3c3.zip?Expires=1667997639&OSSAccessKeyId=STS.NV4w6jF318mTXBo5S5kWAiwUw&Signature=XuzO6aJ%2FcesPCM%2BTHIS4KGRSOlQ%3D&response-content-disposition=attachment%3Bfilename%3D%22example-voting-app-master.zip%22&Date=1667997639&security-token=CAISgwJ1q6Ft5B2yfSjIr5WBPIzeq%2BwQj6%2B%2FWmTe0VNgZ9hthrL%2BlTz2IHxFf3FoCOEYv%2Fk1nWlU6%2FoTlqF%2FTIBDQUvNYZOVTQTbXFvzDbDasumZsJYw6vT8a1fxZjf%2F2MjNGaCbKPrWZvaqbX3diyZ32sGUXD6%2BXlujQ%2BDr6Zl8dYY4UxX6D1tBH8wEAgp5tI1gQhm3D%2Fu2NQPwiWf9FVdhvhEG6Vly8qOi2MaRmHG85R%2FYsrZJ%2FtuvecD%2FMJI3Z8kvC4uPsbYoJvab4kl58ANX8ap6tqtA9Arcs8uVa1sruEnXaLKMo4wxfVIjP%2FFmRvIVtprnieY9tuiWkJ%2Fs25qImF%2BBkY61GoABVf%2BNTaHYQqbDW%2F10rRECk0IdKdoxPoU%2FFQtmAiBMcjW3ZiN%2FoR9gAX1LHZTeBCSuUjhP3L1iOYDIjmz02TDsZCoE3hd%2FF%2FKYYr6fqapSpr8CVLmdZNf2x5rHUWr0Awk%2B9QGx8%2Bzhw%2FZyCNAlsmyGIAg%2Fx4PXQnLsF4KEySlsy2o%3D
  5. $ mkdir -pv example-voting-app ; cd example-voting-app
  6. # 将压缩包进行解压
  7. $ unzip example-voting-app-master.zip
  8. $ cd example-voting-app-master
  9. # 运行Docker-Compose
  10. $ docker-compose up -d
  11. # 需要等待一定时间(大约10分钟)
  12. $ docker-compose ps -a
  13. NAME COMMAND SERVICE STATUS PORTS
  14. example-voting-app-master-db-1 "docker-entrypoint.s…" db running (healthy) 5432/tcp
  15. example-voting-app-master-redis-1 "docker-entrypoint.s…" redis running (healthy) 0.0.0.0:49153->6379/tcp, :::49153->6379/tcp
  16. example-voting-app-master-result-1 "docker-entrypoint.s…" result running 0.0.0.0:5858->5858/tcp, :::5858->5858/tcp, 0.0.0.0:5001->80/tcp, :::5001->80/tcp
  17. example-voting-app-master-vote-1 "python app.py" vote running 0.0.0.0:5000->80/tcp, :::5000->80/tcp
  18. example-voting-app-master-worker-1 "dotnet Worker.dll" worker running

使用浏览器进行访问:

  1. # 投票的页面
  2. http://10.0.0.54:5000/
  3. # 统计的页面
  4. http://10.0.0.54:5001/

💫31 Docker Base - 图96

💫31 Docker Base - 图97

:::color5 Docker-Compose 是一个用于本地开发的工具和用于单机容器编排的工具!

不太适用于集群环境中的使用。

:::