Docker基础

文章目录

    • [1. Docker简介](#1. Docker简介)
    • [2. Docker安装](#2. Docker安装)
    • [3. Docker常用命令](#3. Docker常用命令)
      • [3.1 帮助命令](#3.1 帮助命令)
      • [3.2 镜像的基本命令](#3.2 镜像的基本命令)
      • [3.3 容器的基本命令](#3.3 容器的基本命令)
      • [3.5 常用其他命令](#3.5 常用其他命令)
      • [3.6 练习](#3.6 练习)
    • [4. Protainer可视化面板](#4. Protainer可视化面板)
    • [5. Docker镜像](#5. Docker镜像)
    • [6. 容器数据卷](#6. 容器数据卷)
      • [6.1 使用命令来挂载 -v](#6.1 使用命令来挂载 -v)
      • [6.2 Dockerfile挂载](#6.2 Dockerfile挂载)
      • [6.3 数据卷容器](#6.3 数据卷容器)
    • [7. DockerFile](#7. DockerFile)
      • [7.1 介绍](#7.1 介绍)
      • [7.2 构建过程](#7.2 构建过程)
      • [7.3 DockerFile指令](#7.3 DockerFile指令)
    • [8. 发布镜像](#8. 发布镜像)
      • [8.1 发布镜像到Docker Hub](#8.1 发布镜像到Docker Hub)
      • [8.2 发布镜像到阿里云容器服务](#8.2 发布镜像到阿里云容器服务)
    • [9. Docker网络原理](#9. Docker网络原理)
      • [9.1 理解Docker网络](#9.1 理解Docker网络)
      • [9.2 -link](#9.2 -link)
      • [9.3 自定义网络](#9.3 自定义网络)
      • [9.4 网络连通](#9.4 网络连通)
    • [10. 部署Redis集群实战](#10. 部署Redis集群实战)
    • [11. SpringBoot微服务打包Docker镜像](#11. SpringBoot微服务打包Docker镜像)

1. Docker简介

Docker是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可抑制的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化。容器完全使用沙盒机制,相互之间不会存在任何接口。几乎没有性能开销,可以很容易的在机器和数据中心运行。最重要的是,他们不依赖于任何语言、框架或者包装系统。

DevOps:开发+运维

传统:一堆帮助文档,安装程序

Docker:打包镜像,发布测试,一键运行

使用了Docker之后,我们部署应用就像搭积木一样。

Docker之所以发展如此迅速,因为它提供了系统平滑移植,容器虚拟化技术。

开发人员利用Docker可以消除协作编码时,"在我的机器上可正常工作"的问题。

Docker是dotCloud公司开源的一个基于LXC的高级容器引擎,源码托管在Github上,基于go语言并且遵从Apache2.0协议开源。

GitHub地址:https://github.com/moby/moby

docker官网:https://www.docker.com

docker中文库:https://www.docker.org.cn/

docker hub:https://hub.docker.com/

LXC为Linux Container的简写。Linux Container 容器是一种内核虚拟化技术,可以提供轻量级的虚拟化,以便隔离进程和资源,而且不需要提供指令解释机制以及全虚拟化的其他复杂性。

LXC主要通过Kernel的namespace实现每个用户实例之间的项目隔离,通过cgroup实现对资源的配额和调度。

docker和容器技术和虚拟机技术,都是虚拟化技术。

不同点:

DOcker容器是在操作系统层面上实现虚拟化,直接复用本地主机的操作系统,而传统虚拟机则是在硬件层面实现虚拟化。

与传统的虚拟机相比,Docker优势体现为启动速度快,占用体积小。

容器内的应用进程直接运行于宿主的内核,容器内没有自己的内核且也没有进行硬件虚拟。因此容器比传统虚拟机更为轻便。

每个容器之间互相隔离,每个容器有自己的文件系统,容器之间进程不会互相影响,能区分计算资源。

Docker的出现,就是为了解决运行环境和配置问题的软件容器,方便做持续集成并有助于整体发布的容器虚拟化技术。

Docker整体架构

Docker的基本组成

  • 镜像(image)

    docker镜像好比是一个模版,可以通过这个模版来创建容器服务,tomcat镜像->run->tomcat01容器(提供服务),通过这个镜像可以创建多个容器(最终服务运行或者项目运行就是在容器中的)。

  • 容器(container)

    Docker利用容器技术,独立运行一个或者一组应用,通过镜像来创建。拥有启动、停止、删除等基本命令。可以把容器理解为一个简易的Linux系统。

  • 仓库(repository)

    仓库就是存放镜像的地方。仓库分为共有仓库和私有仓库。如Docker Hub(官方),阿里云,华为云都有容器服务。仓库默认使用的是Docker Hub,是国外的,国内访问速度非常慢,所以要配置镜像加速(像Maven配置镜像一样)。

Docker利用容器(Container)独立运行的一个或一组应用,应用程序或服务运行在容器里面,容器就类似于一个虚拟化的运行环境,容器是用镜像创建的运行实例。就像是Java中的类和实例对象一样,镜像是静态的定义,容器是镜像运行时的实体。容器为镜像提供了一个标准的和隔离的运行环境,它可以被启动、开始、停止、删除。每个容器都是相互隔离的、保证安全的平台。

可以把容器看作是一个简易版的Linux环境(包括root用户权限、进程空间、用户空间和网络空间等)和运行在其中的应用程序。

仓库是集中存放镜像文件的场所,docker提供的官方registry被称为Docker Hub。

仓库分为公开仓库和私有仓库两种形式。最大的公开仓库就是Docker Hub,国内的公开仓库包括阿里云、网易云等。


2. Docker安装

Docker并非是一个通用的容器工具,它依赖于已经存在并运行的Linux内核环境。

DOcker实质上是在已经运行的Linux下制造了一个隔离的文件环境,因此它执行的效率几乎等同于所部署的Linux主机。

因此,Docker必须部署在Linux内核的系统上。如果其他系统想部署Docker就必须安装一个Linux环境。

查看环境信息

shell 复制代码
# 系统内核版本在3.10以上
[root@iZbp13w34ju4eg8v1cixguZ ~]# uname -r
3.10.0-1160.105.1.el7.x86_64

# 查看系统版本
[root@iZbp13w34ju4eg8v1cixguZ ~]# cat /etc/os-release
NAME="CentOS Linux"
VERSION="7 (Core)"
ID="centos"
ID_LIKE="rhel fedora"
VERSION_ID="7"
PRETTY_NAME="CentOS Linux 7 (Core)"
ANSI_COLOR="0;31"
CPE_NAME="cpe:/o:centos:centos:7"
HOME_URL="https://www.centos.org/"
BUG_REPORT_URL="https://bugs.centos.org/"

CENTOS_MANTISBT_PROJECT="CentOS-7"
CENTOS_MANTISBT_PROJECT_VERSION="7"
REDHAT_SUPPORT_PRODUCT="centos"
REDHAT_SUPPORT_PRODUCT_VERSION="7

安装(使用rpm存储库安装)

官方教程:https://docs.docker.com/engine/install/centos/

1.卸载旧的版本

旧版本的 Docker 采用dockerdocker-engine。在尝试安装新版本之前卸载任何此类旧版本以及相关的依赖项。

shell 复制代码
sudo yum remove docker \
                docker-client \
                docker-client-latest \
                docker-common \
                docker-latest \
                docker-latest-logrotate \
                docker-logrotate \
                docker-engine

yum可能会报告没有安装这些软件包。

/var/lib/docker/卸载 Docker 时,不会自动删除存储的映像、容器、卷和网络。

2.需要的软件包

安装yum-utils软件包(提供yum-config-manager 实用程序)

shell 复制代码
[root@iZbp13w34ju4eg8v1cixguZ ~]# sudo yum install -y yum-utils

3.设置镜像的仓库

shell 复制代码
# 使用国内的阿里云
[root@iZbp13w34ju4eg8v1cixguZ ~]# sudo yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo 

3.更新yum软件包索引

shell 复制代码
[root@iZbp13w34ju4eg8v1cixguZ ~]# yum makecache fast

4.安装Docker引擎

shell 复制代码
# docker-ce 社区版    docker-ee 企业版
[root@iZbp13w34ju4eg8v1cixguZ ~]# sudo yum install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

5.启动docker

shell 复制代码
[root@iZbp13w34ju4eg8v1cixguZ ~]# sudo systemctl start docker  # 启动docker
[root@iZbp13w34ju4eg8v1cixguZ ~]# docker version  # 查看版本成功,如果有信息则启动成功
Client: Docker Engine - Community
 Version:           26.0.0
 API version:       1.45
 Go version:        go1.21.8
 Git commit:        2ae903e
 Built:             Wed Mar 20 15:21:09 2024
 OS/Arch:           linux/amd64
 Context:           default

Server: Docker Engine - Community
 Engine:
  Version:          26.0.0
  API version:      1.45 (minimum version 1.24)
  Go version:       go1.21.8
  Git commit:       8b79278
  Built:            Wed Mar 20 15:20:06 2024
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          1.6.28
  GitCommit:        ae07eda36dd25f8a1b98dfbf587313b99c0190bb
 runc:
  Version:          1.1.12
  GitCommit:        v1.1.12-0-g51d5e94
 docker-init:
  Version:          0.19.0
  GitCommit:        de40ad0

6.通过运行镜像来验证Docker是否安装成功hello-world

shell 复制代码
[root@iZbp13w34ju4eg8v1cixguZ ~]# sudo docker run hello-world

7.查看下载的hello-world镜像

shell 复制代码
[root@iZbp13w34ju4eg8v1cixguZ ~]# docker images
REPOSITORY    TAG       IMAGE ID       CREATED         SIZE
hello-world   latest    d2c94e258dcb   10 months ago   13.3kB

卸载Docker

1.卸载 Docker Engine、CLI、containerd 和 Docker Compose 软件包:

shell 复制代码
sudo yum remove docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin docker-ce-rootless-extras

2.主机上的映像、容器、卷或自定义配置文件不会自动删除。要删除所有映像、容器和卷:

shell 复制代码
sudo rm -rf /var/lib/docker
sudo rm -rf /var/lib/containerd

Docker默认工作路径:/var/lib/docker

配置阿里云镜像加速

安装完成后,其实我们的镜像仓库速度还不够快,上面我们设置的阿里云镜像仓库是阿里云内部的,这里我们可以再配置一个阿里云的镜像加速。

进入容器加速服务的控制台,点击左侧边栏的镜像工具下的镜像加速器,查看操作文档。

针对Docker客户端版本大雨1.10.0的用户,可以通过修改daemon配置文件/etc/docker/daemon.json来使用加速器

shell 复制代码
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": ["https://xxxx.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker

这样,阿里云容器加速就配置完成了。

Run的流程

Docker原理

Docker是怎么工作的?

DOcker是一个Client-Server结构的系统,Docker的守护进程运行在主机上,通过Socket从客户端进行访问。

DockerServer接收到Docker-Client的指令就会执行这个命令。


3. Docker常用命令

3.1 帮助命令

shell 复制代码
[root@iZbp13w34ju4eg8v1cixguZ ~]# docker version # 查看docker版本信息
[root@iZbp13w34ju4eg8v1cixguZ ~]# docker info  # 查看docker系统信息,包括镜像和容器的数量
[root@iZbp13w34ju4eg8v1cixguZ ~]# docker 命令 --help  # 查看命令的帮助信息

官方文档:https://docs.docker.com/reference/#command-line-interfaces-clis

3.2 镜像的基本命令

shell 复制代码
[root@iZbp13w34ju4eg8v1cixguZ ~]# docker images # 查看本地主机上所有的镜像
[root@iZbp13w34ju4eg8v1cixguZ ~]# docker image list  # 查看本地主机上所有的镜像
[root@iZbp13w34ju4eg8v1cixguZ ~]# docker images -a  # 列出所有镜像,也可以写成--all

[root@iZbp13w34ju4eg8v1cixguZ ~]# REPOSITORY    TAG       IMAGE ID       CREATED         SIZE
[root@iZbp13w34ju4eg8v1cixguZ ~]# hello-world   latest    d2c94e258dcb   10 months ago   13.3kB

解释:

  • REPOSITORY:仓库源
  • TAG:镜像的标签
  • IMAGE ID:镜像的ID
  • CREATED:镜像的创建时间
  • SIZE:镜像的大小

只显示镜像的ID信息

shell 复制代码
[root@iZbp13w34ju4eg8v1cixguZ ~]# docker images -q  # 只显示镜像的ID,也可以写成--quiet

显示完整的镜像ID

shell 复制代码
[root@iZbp13w34ju4eg8v1cixguZ ~]# docker images --no-trunc # 列出完整长度的镜像ID

显示出镜像的摘要信息

shell 复制代码
[root@iZbp13w34ju4eg8v1cixguZ ~]# docker images --digests # 列出摘要

根据名称或者标签进行镜像显示

shell 复制代码
[root@iZbp13w34ju4eg8v1cixguZ ~]# docker images java  # 按名次列出镜像
[root@iZbp13w34ju4eg8v1cixguZ ~]# dokcer images java:8 # 按名次和标签列出镜像

对镜像进行过滤

shell 复制代码
[root@iZbp13w34ju4eg8v1cixguZ ~]# docker images --filter "dangling=true" --filter "bif=baz"  # 过滤,可以同时存在多个过滤器  可以简写为 -f
[root@iZbp13w34ju4eg8v1cixguZ ~]# docker images -f "before=image1"  # 按时间过滤,显示指定镜像之前创建的镜像,可以使用before,since

格式化输出

shell 复制代码
[root@iZbp13w34ju4eg8v1cixguZ ~]# docker images --format "table {{.ID}}\t{{.Repository}}"
[root@iZbp13w34ju4eg8v1cixguZ ~]# docker images --format json  # 格式化json输出
占位符 描述
.ID 图像ID
.Repository 图片库
.Tag 图片标签
.Digest 图像摘要
.CreatedSince 自创建图像以来经过的时间
.CreatedAt 图像创建时间
.Size 镜像盘大小

搜索镜像

shell 复制代码
[root@iZbp13w34ju4eg8v1cixguZ ~]# docker search [OPTIONS] TERM
选项 默认 描述
-f, --filter 根据提供的条件过滤输出
--format 使用 Go 模板进行漂亮的打印搜索
--limit 最大搜索结果数
--no-trunc 不要截断输出

如:

shell 复制代码
[root@iZbp13w34ju4eg8v1cixguZ ~]# docker search mysql # 搜索mysql

NAME                            DESCRIPTION                                      STARS     OFFICIAL
mysql                           MySQL is a widely used, open-source relation...   14971     [OK]
mariadb                         MariaDB Server is a high performing open sou...   5710      [OK]
percona                         Percona Server is a fork of the MySQL relati...   627       [OK]
phpmyadmin                      phpMyAdmin - A web interface for MySQL and M...   962       [OK]

[root@iZbp13w34ju4eg8v1cixguZ ~]# docker search -f stars=5000 mysql
NAME      DESCRIPTION                                      STARS     OFFICIAL
mysql     MySQL is a widely used, open-source relation...   14971     [OK]
mariadb   MariaDB Server is a high performing open sou...   5710      [OK]

[root@iZbp13w34ju4eg8v1cixguZ ~]# docker search mysql --limit=1
NAME      DESCRIPTION                                      STARS     OFFICIAL
mysql     MySQL is a widely used, open-source relation...   14971     [OK]

下载镜像

shell 复制代码
[root@iZbp13w34ju4eg8v1cixguZ ~]# docker pull [OPTIONS] NAME[:TAG|@DIGEST]
或者
[root@iZbp13w34ju4eg8v1cixguZ ~]# docker image pull [OPTIONS] NAME[:TAG|@DIGEST]
选项 默认 描述
-a, --all-tags 下载存储库中所有标记的图像
--disable-content-trust true 跳过图像验证
--platform API 1.32+ 如果服务器支持多平台,则设置平台
-q, --quiet 抑制详细输出

如:

shell 复制代码
[root@iZbp13w34ju4eg8v1cixguZ ~]# docker pull mysql
Using default tag: latest  # 如果不指定TAG,则默认下载最新版
latest: Pulling from library/mysql
72a69066d2fe: Pull complete    # 分层下载,docker iamge的核心  联合文件系统
93619dbc5b36: Pull complete 
99da31dd6142: Pull complete 
626033c43d70: Pull complete 
37d5d7efb64e: Pull complete 
ac563158d721: Pull complete 
d2ba16033dad: Pull complete 
688ba7d5c01a: Pull complete 
00e060b6d11d: Pull complete 
1c04857f594f: Pull complete 
4d7cfa90e6ea: Pull complete 
e0431212d27d: Pull complete 
Digest: sha256:e9027fe4d91c0153429607251656806cc784e914937271037f7738bd5b8e7709  # 签名
Status: Downloaded newer image for mysql:latest
docker.io/library/mysql:latest   # 真实地址

[root@iZbp13w34ju4eg8v1cixguZ ~]# docker pull docker.io/library/mysql:latest   # 与上面命令等价

[root@iZbp13w34ju4eg8v1cixguZ ~]# docker pull mysql:8.0.20    # 通过指定TAG,指定版本下载

删除镜像

删除可以通过镜像的ID进行删除,可以通过镜像的名称进行删除

shell 复制代码
[root@iZbp13w34ju4eg8v1cixguZ ~]# docker image rm [OPTIONS] IMAGE [IMAGE...]
或者
[root@iZbp13w34ju4eg8v1cixguZ ~]# docker image remove
或者
[root@iZbp13w34ju4eg8v1cixguZ ~]# docker rmi
选项 默认 描述
-f, --force 强制删除图像
--no-prune 不要删除未标记的父项

如:

shell 复制代码
[root@iZbp13w34ju4eg8v1cixguZ ~]# docker rmi be0dbf01a0f3  # 指定ID进行删除

[root@iZbp13w34ju4eg8v1cixguZ ~]# docker rmi ID1 ID2 ID3  # 一次删除多个容器

[root@iZbp13w34ju4eg8v1cixguZ ~]# docker rmi -f $(docker images -aq)  # 删除所有镜像

#  $():是指以参数形式传递进去

3.3 容器的基本命令

有了镜像,才可以创建容器!

下载centos镜像

shell 复制代码
[root@iZbp13w34ju4eg8v1cixguZ /]# docker pull centos

新建容器并启动

shell 复制代码
dokcer run [可选参数] image  # 启动镜像

常用参数:

  • --name="Name":容器名字,如tomcat01,tomcat02,用来区分容器
  • -d::后台方式运行
  • -it:使用交互方式运行,进入容器查看内容
  • -p:指定容器端口
    • 方式一:-p 主机端口 : 容器端口(常用)
    • 方式二:-p 容器端口
    • 方式三:容器端口
    • 方式四:-p ip : 主机端口 : 容器端口
  • -P:大写则是随机指定端口

如:

shell 复制代码
# 启动centos 并使用交互模式进入容器 交互工具使用bash
[root@iZbp13w34ju4eg8v1cixguZ /]# docker run -it centos /bin/bash 
[root@a6fef307536f /]#       
# 此时已经进入了容器,进入了docker镜像创建的centos中了,该centos为基础版本,很多命令甚至都是不完善的

# 退出容器 从容器中退回主机 容器并且停止
[root@a6fef307536f /]# exit
exit
[root@iZbp13w34ju4eg8v1cixguZ /]# 

列出所有运行中的容器

shell 复制代码
[root@iZbp13w34ju4eg8v1cixguZ /]# docker ps  # 查看正在运行的容器

[root@iZbp13w34ju4eg8v1cixguZ /]# docker ps -a   # 查看历史运行的容器

常用参数:

  • -a:列出当前正在运行的容器,并且列出历史运行过的程序
  • -n=个数:显示最近创建的容器,指定格式
  • -q:只显示容器编号

退出容器

shell 复制代码
exit   # 容器停止并退出
# 通过快捷键 Ctrl+P+Q:容器不停止退出

进入容器

shell 复制代码
# 通过使用 exec命令进入容器
[root@iZbp13w34ju4eg8v1cixguZ /]# docker exec -it centos1 /bin/bash
或者
[root@iZbp13w34ju4eg8v1cixguZ /]# docker exec -it centos1 bash

# 通过使用 attach命令进入容器
[root@iZbp13w34ju4eg8v1cixguZ /]# docker attach centos1 

注意:这两种方式存在不同,使用exec进入容器时,退出容器时使用exit不会使容器停止,但是使用attach命令进入容器后,使用exit命令会使容器停止。

exec:进入容器后,开启一个新的终端

attach:进入容器正在执行的终端,不会启动新的进程

删除容器

shell 复制代码
docker rm 容器id/容器名称
docker rm -f $(docker ps -aq)  # 删除全部容器
docker ps -a -q|xargs docker rm  # 运用linux的管道符删除全部容器

注意:运行中的容器不能直接删除,如果要删除运行中的容器,需要使用命令rm -f进行强制删除

启动/停止容器

bash 复制代码
docker start 容器ID/容器名称       # 启动容器
docker restart 容器ID/容器名称    # 重启容器
docker stop 容器ID/容器名称        # 停止当前正在运行的容器
docker kill 容器ID/容器名称        # 强制停止当前容器

3.5 常用其他命令

后台启动容器

shell 复制代码
[root@iZbp13w34ju4eg8v1cixguZ /]# docker run -dit --name centos1 centos bash    # 通过指定参数 -d 来指定后台运行

但是当我们执行下面命令时

bash 复制代码
docker run -d centos

然后后执行docker ps,会发现centos已经停止了。容器使用后台运行时,就必须要有一个前台进程,如果没有前台进程,docker就会发现没有对外提供服务的应用,就会自动停止。

查看日志

bash 复制代码
docker logs

常用参数:

选项 默认 描述
--details 显示提供给日志的额外详细信息
-f, --follow 跟随日志输出
--since 显示自时间戳(例如2013-01-02T13:23:37Z)或相对时间(例如42m42 分钟)以来的日志
-n, --tail all 从日志末尾开始显示的行数
-t, --timestamps 显示时间戳
--until API 1.35+ 在时间戳(例如2013-01-02T13:23:37Z)或相对时间(例如42m42 分钟)之前显示日志

查看容器中的进程信息

bash 复制代码
docker top 容器ID/名称

查看镜像元数据

shell 复制代码
docker inspect 容器ID/名称

参数:

选项 默认 描述
-f, --format 使用自定义模板设置输出格式: 'json':以 JSON 格式打印 'TEMPLATE':使用给定的 Go 模板打印输出。
-s, --size 显示总文件大小

从容器内拷贝文件到主机上

shell 复制代码
docker cp 容器:容器内路径 目的主机路径

如:

shell 复制代码
docker cp centos1:/home/test.py /home  # 从容器内拷贝到主机
docker cp /home/my.py centos1:/home    # 从主机拷贝到容器内

一般从主机拷贝到容器内,不实用cp命令进行拷贝,我们一般使用挂载!

拷贝是一个手动过程,未来我们使用-v卷的技术,可以实现主机目录与容器内目录同步。

查看cpu状态

shell 复制代码
docker stats

3.6 练习

shell 复制代码
docker search -f starts=100 nginx  # 搜索nginx镜像
dokcer pull nginx     # 下载镜像
dokcer run -d --name nginx1 -p 3344:80 nginx   # 通过镜像创建容器并启动 主机端口3344映射到容器端口80

按照上面的操作,我们就可以通过公网ip:3344访问nginx

配置tomcat

shell 复制代码
docker pull tomcat:90.  # 下载镜像 指定版本

docker run -it --rm -p 8888:8080 tomcat   # 启动容器

启动后访问公网ip:8888即可访问,但是出现404,因为docker镜像的tomcat是阉割版本

--rm:停止了容器后,自动删除容器,一般用来测试,用完即删

部署es

shell 复制代码
# es 暴露的端口很多
# es 十分的耗内存
# es 的数据一般需要放置到安全目录! 挂载
# --net somenetwork ? 网络配置
# -e:环境配置修改


# 启动 elasticsearch
docker run -d --name es -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" elasticsearch:7.6.2

docker stop es  # 关闭es

docker run -d --name es02 -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -e ES_JAVA_OPTS="-Xms64m -Xmx512m" elasticsearch:7.6.2  # 启动 并限制内存

4. Protainer可视化面板

Protainer是docker图像化界面管理工具,提供一个后台面板供我们操作!

shell 复制代码
docker run -d -p 8088:9000 --restart=always -v /var/run/docker.sock:/var/run/docker.sock --privileged=true portainer/portainer

访问测试:

访问公网IP:8088,即可访问到管理页面。

首先,设置密码

设置数据,一般是选择本地数据Local

成功进入!


5. Docker镜像

Docker镜像是什么?

镜像是一种轻量级、可执行的独立软件包,用来打包软件运行环境和基本运行环境开发的软件,它包含运行某个软件所需的所有内容,包括代码、运行时、库、环境变量和配置文件。

UnionFS(联合文件系统)

UnionFS:Union文件系统是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同的目录挂载到同一个虚拟文件系统下。Union文件系统是Docker镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。

特性:一次同时加载多个文件系统,但是从外面来看,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录。

我们下载的时候看到的一层层就是这个!

Docker镜像家加载原理

docker的镜像实际上由一层一层的文件系统组成,这种层级的文件系统UnionFS。 bootfs(boot file system)主要包含bootloader和kernel, bootloader主要是引导加载kernel, Linux刚启动时会加载bootfs文件系统,在Docker镜像的最底层是bootfs。这一层与我们典型的Linux/Unix系统是一样的,包含boot加载器和内核。当boot加载完成之后整个内核就都在内存中了,此时内存的使用权已由bootfs转交给内核,此时系统也会卸载bootfs。

rootfs (root file system) ,在bootfs之上。包含的就是典型 Linux 系统中的 /dev, /proc, /bin, /etc 等标准目录和文件。rootfs就是各种不同的操作系统发行版,比如Ubuntu,Centos等等。

平时我们安装虚拟机的CentOs都是好几个G,为什么docker才几百M

对于一个精简的OS,rootfs可以很小,只需要包括最基本的命令、工具和程序库就可以了,因为底层直接用Host的kernel,自己只需要提供 rootfs 就行了。由此可见对于不同的linux发行版, bootfs基本是一致的, rootfs会有差别, 因此不同的发行版可以公用bootfs。

分层理解

下载docker镜像时一层一层的其实就是分层最直观的体现(已经下载过得不会重复下载)

我们还可以通过inspect命令看到分层的具体信息,如

shell 复制代码
docker image inspect nginx:latest

"RootFS": {
    "Type": "layers",
    "Layers": [
        "sha256:2edcec3590a4ec7f40cf0743c15d78fb39d8326bc029073b41ef9727da6c851f",
        "sha256:e379e8aedd4d72bb4c529a4ca07a4e4d230b5a1d3f7a61bc80179e8f02421ad8",
        "sha256:b8d6e692a25e11b0d32c5c3dd544b71b1085ddc1fddad08e68cbd7fda7f70221",
        "sha256:f1db227348d0a5e0b99b15a096d930d1a69db7474a1847acbc31f05e4ef8df8c",
        "sha256:32ce5f6a5106cc637d09a98289782edf47c32cb082dc475dd47cbf19a4f866da",
        "sha256:d874fd2bc83bb3322b566df739681fbd2248c58d3369cb25908d68e7ed6040a6"
    ]
}

分层的好处

最大的一个好处就是 - 共享资源

比如:有多个镜像都从相同的 base 镜像构建而来,那么 Docker Host 只需在磁盘上保存一份 base 镜像;同时内存中也只需加载一份 base 镜像,就可以为所有容器服务了。而且镜像的每一层都可以被共享。

这时可能就有人会问了:如果多个容器共享一份基础镜像,当某个容器修改了基础镜像的内容,比如 /etc 下的文件,这时其他容器的 /etc 是否也会被修改? 答案:不会!因为修改会被限制在单个容器内。

Docker镜像都是只读的,当容器启动时,一个新的可写层被加载到镜像的顶部。

这一层就是我们通常说的容器层,容器之下的都叫做镜像层。所有操作都是针对容器层的,只有容器层是可写的,容器层下面的所有镜像层都是只读的。

commit镜像

容器提交为镜像

shell 复制代码
# docker commit 提交容器称为一个新的副本

docker commit -m="提交的描述信息" -a="作者" 容器ID 目标镜像名:[TAG]

[root@iZbp13w34ju4eg8v1cixguZ /]# docer commit -m "my tomcat" -a "codewei" tomcat01 mytomcat01:1.0

6. 容器数据卷

需求:希望数据可以存储在本地,不存储在容器内

容器与主机之间可以有一个数据共享的技术!那么就是容器数据卷。

Docker容器中产生的数据,可以同步到本地。

也就是目录挂载,将我们容器内到目录,挂载到宿主机上面。

数据卷就是为了容器的持久化和同步操作。

容器间也是可以数据共享的。

6.1 使用命令来挂载 -v

shell 复制代码
docker run -it -v 主机目录地址:容器内目录

docker run -it --name centos2 -v /home/test:/home centos /bin/bash

这样,在容器内的/home目录下创建文件,在本地宿主机上也可以看到这个创建的文件。

安装MySQL

shell 复制代码
# 获取镜像
docker pull mysql:5.7

# 运行容器,做数据挂载
# 注意:安装启动mysql的时候,是需要配置密码的!
# -d 后台运行 -p 端口映射 --name 名字  -v 数据集挂载  -e 环境配置

docker run -d -p 8888:3306 --name mysql01 -v /home/mysql/conf:/etc/mysql/conf.d -v /home/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=shw123zxc mysql:5.7

这样就实现了mysql数据挂载到了本地!

具名和匿名挂载

匿名挂载:匿名挂载就是在指定数据卷的时候,不指定容器路径对应的主机路径,这样对应映射的主机路径就是默认的路径/var/lib/docker/volumes/中自动生成一个随机命名的文件夹。

只指定容器内目录,不指定容器外目录

shell 复制代码
docker run -d -P --name nginx01 -v /etc/nginx nginx

具名挂载:具名挂载,就是指定文件夹名称,区别于指定路径挂载,这里的指定文件夹名称是在Docker指定的默认数据卷路径下的。

shell 复制代码
docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx nginx  

注意!上面这个命令juming-nginx前面没有斜杠/,一旦加了斜杠就成为了目录地址,这样不加,就是名字

通过docker volume查看所有卷的情况

shell 复制代码
docker volume ls

通过命令,查看具名挂载卷到本地的目录信息

shell 复制代码
docker volume inspect 卷名

具名挂载和匿名挂载会挂载到Docker指定的默认数据卷路径下:/var/lib/docker/volumes/xxxx/_data

Mac系统是在:/usr/local/lib/docker

我们通过具名挂载可以方便的找到我们的卷,大多数情况都会使用具名挂载

总结:

-v 容器内路径 # 匿名挂载

-v 卷名:容器内路径 # 具名挂载

-v /主机目录:容器内目录 # 指定路径挂载

拓展:

一旦设定了容器权限,容器对我们挂载出来的内容就有限定了!

shell 复制代码
docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx:ro nginx
docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx:rw nginx

ro:read-only,只读

rw:readwrite,可读可写

只要看到ro,就说明,这个指定的目录只能通过宿主机来操作,容器内部无法操作!!

6.2 Dockerfile挂载

Dockerfile就是用来构建docker镜像文件的构建文件!

通过这个脚本文件可以生成镜像,镜像是一层层的,脚本是一个一个的命令,每个命令都是一层。

编写Dockerfile

创建dockerfile文件,名字可以随意,但是建议是dockerfile

注意:dockerfile中的名字全部都是大写的

这里的每个命令,就是镜像的一层

shell 复制代码
#  指令  参数
FROM centos 
 
VOLUME ["volume01","volume02"]   # 挂载卷 匿名挂载两个卷

CMD echo "----success----"   # 调用cmd输出
CMD /bin/bash    # 调用cmd 运行bash

通过Dockerfile构建镜像

shell 复制代码
docker build -f dockerfile1 -t codewei/centos:1.0 .
# -f  指定dockerfile路径
# -t  镜像名称
# . 

通过镜像创建容器,并启动容器

shell 复制代码
docker run -it --name mycentos codewei/centos:1.0 /bin/bash

# 通过下面命令,可以查看容器中目录挂载到的位置
dokcer inspect 容器id/容器名称

这种方式,我们使用的非常多!

不可以通过Dockerfile进行具名挂载

6.3 数据卷容器

两个容器之间共享同步数据。例如,两个mysql同步数据。

通过我们刚才自己写的镜像,启动三个容器

shell 复制代码
docker run -it --name centos01 codewei/centos:1.0 /bin/bash
docker run -it --name centos02 --volumes-from centos01 codewei/centos:1.0 /bin/bash
docker run -it --name centos03 --volumes-from centos01 codewei/centos:1.0 /bin/bash

这样,在centos02中的volume01中创建文件,在centos01volume01中也能看得到,这样就是将centos02挂载了centos01的目录。这里的centos01就称为数据卷容器。

centos03也挂载centos01,这样在centos02中创建文件,centos3中也会同步。

如果将centos01删除,也不会影响到cenetos2centos3

个人理解:

centos1是挂载了本地目录,假设这个是通过指针指向了本地目录

centos2centos3在启动时挂载centos1所挂载的目录,也就是centos2centos3会继承centos1指向本地的指针

通过--volumes-from看似指向了centos1,其实是centos1将其所挂载的指针给了centos2centos3

疑问解答

**疑问:**如果我在dockerfile1中定义了 VOLUME ["v1","v2"] ,在dockerfile2中定义了VOLUME["v3","v4"] ,然后通过dockerfile1创建镜像并启动了centos1,通过dockerfile2创建了镜像,并且在启动时通过 --volumes-from 指定了centos1,命名这台为centos2,那么centos2如何挂载?

解答:

在这种情况下,centos2 将会挂载 centos1 中定义的卷(v1v2),而不是 centos2 中定义的卷(v3v4)。

当你使用 --volumes-from 参数启动 centos2 时,它将会继承自 centos1 的卷挂载点。换句话说,centos2 将会拥有 centos1 中定义的卷,并将其挂载到相应的路径上,而不会创建 centos2 自己的卷。

因此,无论你在 dockerfile2 中定义了什么卷,centos2 在启动时都会挂载 centos1 中定义的卷。

v3v4会在centos2中存在,但是它不会从本地挂载,只能在容器内部使用,也就相当于是容器内部的目录里。

多个mysql实现数据共享

shell 复制代码
dokcer run -d -p 3340:3306 -v /etc/mysql/conf.d -v /var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql:5.7   # mysql01 通过匿名挂载本地

dokcer run -d -p 3310:3306 --volumes-from mysql01 -e MYSQL_ROOT_PASSWORD=123456 --name mysql02 mysql:5.7  #mysql02挂载mysql01

7. DockerFile

7.1 介绍

dockerfile是用来构建docker镜像的文件。它就是一个命令参数脚本。

构建步骤:

  • 编写一个dockerfile文件
  • docker build构建成为一个镜像
  • docker run运行镜像
  • docker push发布镜像(发布到DockerHub、阿里云镜像仓库)

很多官方镜像都是基础包,很多功能没有,我们通常会自己搭建自己的镜像。

7.2 构建过程

基础知识:

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

dockerfile是面向开发的,我们以后要发布项目,做镜像,就需要编写dockerfile文件,这个文件十分简单。

Docker镜像逐渐成为企业交付的标准。

DockerFile:构建文件,定义了一切的步骤。

DockerImages:通过DockerFile构建生成的镜像,最终发布和运行的产品。

Docker容器:容器就是镜像运行起来提供服务的。

7.3 DockerFile指令

  • From:基础镜像,一切从这里开始构建,如centos等
  • MAINTAINER:镜像是谁写的,一般留姓名+邮箱
  • RUN:镜像构建的时候需要运行的命令
  • ADD:添加内容,如果我们要建一个Tomcat镜像,就通过ADD添加一个tomcat的压缩包
  • WORKDIR:镜像的工作目录
  • VOLUME:设置挂载的目录(匿名挂载)
  • EXPOSE:指定暴露端口
  • CMD:指定这个容器启动的时候要运行的命令,只有最后一个会生效,可被替代
  • ENTRYPOINT:指定这个容器启动的时候要运行的命令,可以追加命令
  • ONBUILD:当构建一个被继承的镜像,这个时候就会运行这个指令,是一个触发指令
  • COPY:类似ADD命令,将文件拷贝到镜像中
  • ENV:构建的时候设置环境变量

实战:构建自己的Centos

Docker Hub中99%的镜像都是从这个基础镜像过来的,From scratch

然后配置需要的软件和配置进行构建

创建自己的Centos:

创建dockerfile文件,mydockerfile-centos

dockerfile 复制代码
FROM centos:7
MAINTAINER codewei<mango_1698@163.com>

ENV MYPATH /usr/local    # 环境变量  key-value
WORKDIR $MYPATH     # $ 取环境看了定义的值

RUN yum -y install vim   # 安装vim
RUN yum -y install net-tools   # 安装net-tools,安装后就可以使用ifconfig命令了

EXPOSE 80   # 暴露端口

CMD echo $MYPATH
CMD echo ------ Success ------
CMD /bin/bash

通过dockerfile,构建镜像

bash 复制代码
docker build -f mydockerfile-centos -t mycentos:1.0 .

通过该镜像创建容器并启动

bash 复制代码
docker run -it --name mycentos mycentos:1.0

我们可以列出本地镜像的变更历史,通过docker history命令

bash 复制代码
docker history mycentos:1.0

CMD和ENTRYPOINT的区别

  • CMD:指定这个容器启动的时候要运行的命令,只有最后一个会生效,可被替代
  • ENTRYPOINT:指定这个容器启动的时候要运行的命令,可以追加命令

测试CMD

创建dockerifle-cmd-test文件

dockerfile 复制代码
FROM centos

CMD ["ls","-a"]

通过该文件构建镜像

bash 复制代码
docker build -f dockerfile-cmd-test -t docker-cmd-test:1.0 .

通过该镜像创建容器并运行

bash 复制代码
docker run docker-cmd-test:1.0

此时,我们看到我们的ls -a命令生效了。如果我们想追加一个参数-l,也就是我们期望执行ls -al

bash 复制代码
docker run docker-cmd-test:1.0 -l

此时,我们发现报错了!

这就是在使用CMD指令的情况下,-l会替换掉CMD所指定的['ls','-a']命令,-l不是一个正确的命令,所以会报错

如果,此时我们想要用ls -al命令的话,就要写完整

bash 复制代码
docker run docker-cmd-test:1.0 ls -al

这样就意味着,ls -al命令替换掉了CMD ['ls','-a'],此时就可以正确执行了。

测试ENTRYPOINT

创建dockerifle-entrypoint-test文件

dockerfile 复制代码
FROM centos

ENTRYPOINT ["ls","-a"]

通过该文件构建镜像

bash 复制代码
docker build -f dockerfile-entrypoint-test -t docker-entrypoint-test:1.0 .

通过该镜像创建容器并运行

bash 复制代码
docker run docker-entrypoint-test:1.0

此时我们想要追加命令-l,可以直接追加,其不会覆盖dockerfile中定义的命令

bash 复制代码
docker run docker-entrypoint-test:1.0 -l

这样,便会执行ls -al

实战:Tomcat镜像

  • 准备镜像文件,tomcat压缩包,jdk压缩包

  • 编写dockerfile文件,官方命名Dockerfile,如果使用了官方命名,我们在执行build命名构建镜像时,就不再需要使用-f参数,它会自动寻找这个文件。

    dockerfile 复制代码
    FROM centos:7
    MAINTAINER codewei<mango_1698@163.com>
    
    COPY readme.txt /usr/local/readme.txt
    
    ADD jdk-8u401-linux-x64.tar.gz /usr/local
    ADD apache-tomcat-9.0.46.tar.gz /usr/local
    
    RUN yum -y install vim
    
    ENV MYPATH /usr/local
    WORKDIR $MYPATH
    
    ENV JAVA_HOME /usr/local/jdk1.8.0_401
    ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
    
    ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.46
    ENV CATALINA_BASH /usr/local/apache-tomcat-9.0.46
    ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin
    
    EXPOSE 8080
    
    CMD /usr/local/apache-tomcat-9.0.46/bin/startup.sh

    使用ADD指令,它会帮我们自动解压

通过该文件,构建镜像diytomcat

bash 复制代码
docker build -t diytomcat .

启动容器

bash 复制代码
docker run -it -p 9999:8080 --name diytomcat01 -v /home/environment/build/tomcat/test:/usr/local/apache-tomcat-9.0.46/webapps/test -v /home/environment/build/tomcatlogs:/usr/local/apache-tomcat-9.0.46/logs diytomcat

访问测试

发布项目(由于做了挂载,所以我们可以直接在本地编写项目就可以发布了)


8. 发布镜像

8.1 发布镜像到Docker Hub

Docker Hub:https://hub.docker.com/

  • 注册自己的账号
  • 在服务器上提交自己的镜像
bash 复制代码
[root@localhost ~]# docker login --help
Usage:  docker login [OPTIONS] [SERVER]
Log in to a Docker registry.
If no server is specified, the default is defined by the daemon.
Options:
  -p, --password string   Password
      --password-stdin    Take the password from stdin
  -u, --username string   Username

登录完毕后提交镜像

bash 复制代码
# 登录
[root@localhost ~]# docker login -u candy821
Password: 
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store
Login Succeeded
# 提交镜像,带上版本号,否则会被拒绝
[root@localhost ~]# docker push diytomcat
Using default tag: latest
The push refers to repository [docker.io/library/diytomcat]
3514cac4541c: Preparing 
b9a3a8ee3650: Preparing 
aac332cceb25: Preparing 
74ddd0ec08fa: Preparing 
denied: requested access to the resource is denied    # 被拒绝
# 解决,重新命名
[root@localhost ~]# docker push candy821/diytomcat:1.0
The push refers to repository [docker.io/candy821/diytomcat]
An image does not exist locally with the tag: candy821/diytomcat
# 重新命名再提交
[root@localhost ~]# docker tag 89f2a31cc01a candy821/tomcat:1.0
[root@localhost ~]# docker push candy821/tomcat:1.0
The push refers to repository [docker.io/candy821/tomcat]
3514cac4541c: Pushed 
b9a3a8ee3650: Pushed 
aac332cceb25: Pushed 
74ddd0ec08fa: Pushed 
1.0: digest: sha256:73540a37afd6060c8989966e0bdc4f9b2906319ce3ed0fe3ba50d11c1ee71bc4 size: 1161

退出登录

bash 复制代码
[root@localhost ~]# docker logout

8.2 发布镜像到阿里云容器服务

1.登录阿里云

2.找到镜像服务

3.创建命名空间

4.创建容器镜像

5.浏览页面信息


9. Docker网络原理

9.1 理解Docker网络

清空所有环境

bash 复制代码
# 删除所有容器
[root@localhost ~]# docker rm -f $(docker ps -aq)
# 删除所有镜像
[root@localhost ~]# docker rmi -f $(docker images -aq)

Docker是如何处理容器网络访问的

bash 复制代码
# 运行容器
[root@localhost ~]# docker run -d -P --name tomcat01 tomcat
# 查看容器内部网络地址
# 若没有被阉割命令
[root@localhost ~]# docker exec -it tomcat01 ip addr
# 若被阉割命令,先进入容器
[root@localhost ~]# docker exec -it tomcat01 /bin/bash
# 再查看
root@3e7a784d1d49:/usr/local/tomcat# cat /etc/hosts
127.0.0.1    localhost
::1    localhost ip6-localhost ip6-loopback
fe00::0    ip6-localnet
ff00::0    ip6-mcastprefix
ff02::1    ip6-allnodes
ff02::2    ip6-allrouters
172.17.0.2    3e7a784d1d49
# Linux能不能ping通容器内部
[root@localhost ~]# ping 172.17.0.2
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.065 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.071 ms
64 bytes from 172.17.0.2: icmp_seq=3 ttl=64 time=0.127 ms
64 bytes from 172.17.0.2: icmp_seq=4 ttl=64 time=0.050 ms
64 bytes from 172.17.0.2: icmp_seq=5 ttl=64 time=0.060 ms
... ...
# Linux可以ping通docker容器内部

原理:

1.每启动一个Docker容器,Docker就会给Docker容器分配一个IP,只要安装了Docker,就会有一个网卡Docker桥接模式,使用的技术是 evth-pair技术再次测试ip addr

2.在启动一个容器测试,发现又多了一对网卡

markdown 复制代码
# 发现这个容器带来的网卡,都是一对一对的
# evth-pair 就是一对虚拟设备接口,他们都是成对出现的,一端连着协议,一端彼此相连
# 正因为有这个特性,evth-pair 充当一个桥梁,连接各种虚拟网络设备的
# OpenStac,Docker容器之间的连接,OVS的连接,都是使用 evth-pair 技术

3.测试 tomcat01 和 tomcat02 是否可以ping通

bash 复制代码
[root@localhost ~]# docker exec -it tomcat02 ping 172.17.0.2
# 结论:容器和容器之间是可以互相ping通的

绘制一个网络模型图:

结论:Tomcat01和Tomcat02是公用的一个路由器,Docker0。

所有的容器不指定网络的情况下,都是Docker0路由的,Docker会给我们的容器分配一个默认的可用IP。

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

Docker中的所有的网络接口都是虚拟的,虚拟的转发效率高!(内网传递文件!)

只要容器删除,对应网桥一对就没了。

思考一个场景:我们编写了一个微服务,database url=ip: ,项目不重启,数据库ip换了,我们希望可以处理这个问题,可以通过名字来进行访问容器?

bash 复制代码
# 如何可以解决呢?
[root@localhost ~]# docker exec -it tomcat02 ping tomcat01
ping: tomcat01: Name or service not known
# 通过 --link 就可以解决网络连通问题
[root@localhost ~]# docker run -d -P --name tomcat03 --link tomcat02 tomcat
8d727b26b070698d3a84db2b6269f1a86edbb1c110a23c2733addef16f6e3bef
[root@localhost ~]# docker exec -it tomcat03 ping tomcat02
# 反向可以ping通吗
[root@localhost ~]# docker exec -it tomcat02 ping tomcat03
ping: tomcat03: Name or service not known
  • 探究:docker network inspect bridge

其实这个tomcat03就是在本地配置了tomcat02的配置

bash 复制代码
# 查看 hosts 配置,原理发现
[root@localhost ~]# docker exec -it tomcat03 cat /etc/hosts
127.0.0.1    localhost
::1    localhost ip6-localhost ip6-loopback
fe00::0    ip6-localnet
ff00::0    ip6-mcastprefix
ff02::1    ip6-allnodes
ff02::2    ip6-allrouters
172.17.0.3    tomcat02 6846b34d8575
172.17.0.4    8d727b26b070

本质探究

---link 就是我们在hosts配置中增加了一个172.17.0.3 tomcat02 6846b34d8575的映射,但是现在学习Docker已经不建议使用 ---link 了,自定义网络不适用于Docker0!!!

Docker0问题:不支持容器名连接访问

9.3 自定义网络

查看所有的Docker网络

bash 复制代码
[root@localhost ~]# docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
7ce5bdb21f44   bridge      bridge      local
cd5de991401c   host         host          local
fbd8caf8d260    none        null           
local

网络模式

  • Bridge:桥接模式,Docker上搭桥
  • None:不配置网络
  • Host:和宿主机共享网络
  • Container:容器内网络连通

测试

bash 复制代码
# 直接启动的命令 --net bridge,这个就是docker0
[root@localhost ~]# docker run -d -P --name tomcat01 --net bridge tomcat
# docker0特点:默认,域名不能访问,--link可以打通连接
# 自定义一个网络!
# --driver bridge
# --subnet 192.168.0.0/16     192.168.0.2-->192.168.255.255
# --gateway 192.168.0.1
[root@localhost ~]# docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
eee16692df425281c8ce3ce0d2d9cd3e98b442ee483e536f28051b75c4e7fea6
[root@localhost ~]# docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
7ce5bdb21f44   bridge    bridge    local
cd5de991401c   host      host      local
eee16692df42   mynet     bridge    local
fbd8caf8d260   none      null      local

自己的网络就创建好了

bash 复制代码
[root@localhost ~]# docker run -d -P --name tomcat-net-01 --net mynet tomcat
eebad75b51ea69848416542d16898efc49fb60a8cfcb10cb013563ca351d6493
[root@localhost ~]# docker run -d -P --name tomcat-net-02 --net mynet tomcat
aa84a57faf837c325c9694e27b3a4290ec6628ee5a92b38123f9525030088773
[root@localhost ~]# docker network inspect mynet
[
    {
        "Name": "mynet",
        "Id": "eee16692df425281c8ce3ce0d2d9cd3e98b442ee483e536f28051b75c4e7fea6",
        "Created": "2021-12-17T07:36:18.272108685+08:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "192.168.0.0/16",
                    "Gateway": "192.168.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
            "aa84a57faf837c325c9694e27b3a4290ec6628ee5a92b38123f9525030088773": {
                "Name": "tomcat-net-02",
                "EndpointID": "8c3923f7409afc7c759f34ef18c0219dda7f09f361b654afcad13382ac2f96f5",
                "MacAddress": "02:42:c0:a8:00:03",
                "IPv4Address": "192.168.0.3/16",
                "IPv6Address": ""
            },
            "eebad75b51ea69848416542d16898efc49fb60a8cfcb10cb013563ca351d6493": {
                "Name": "tomcat-net-01",
                "EndpointID": "2750d27a0fb5a2529fd6261b6c645db98c1597db6f43d84da09de755e1d6f95b",
                "MacAddress": "02:42:c0:a8:00:02",
                "IPv4Address": "192.168.0.2/16",
                "IPv6Address": ""
            }
        },
        "Options": {},
        "Labels": {}
    }
]
# ping不通可能是因为tomcat里没有ping命令,可以换个方式
[root@localhost ~]# docker exec -it tomcat-net-01 ping 192.168.0.3
OCI runtime exec failed: exec failed: container_linux.go:380: starting container process caused: exec: "ping": executable file not found in $PATH: unknown
# 换个方式可以
[root@localhost ~]# docker exec -it tomcat-net-01 curl tomcat-net-02:8080
<!doctype html><html lang="en"><head><title>HTTP Status 404 -- Not Found</title><style type="text/css">body {font-family:Tahoma,Arial,sans-serif;} h1, h2, h3, b {color:white;background-color:#525D76;} h1 {font-size:22px;} h2 {font-size:16px;} h3 {font-size:14px;} p {font-size:12px;} a {color:black;} .line {height:1px;background-color:#525D76;border:none;}</style></head><body><h1>HTTP Status 404 -- Not Found</h1><hr class="line" /><p><b>Type</b> Status Report</p><p><b>Description</b> The origin server did not find a current representation for the target resource or is not willing to disclose that one exists.</p><hr class="line" /><h3>Apache Tomcat/10.0.14</h3></body></html>

自定义的网络docker都已经帮我们维护好了对应的关系,推荐平时这样使用网络!

好处:

Redis - 不同的集群使用不同的网络,保证集群是安全和健康的

MySQL - 不同的集群使用不同的网络,保证集群是安全和健康的

9.4 网络连通

bash 复制代码
# 测试打通 tomcat01 - mynet
[root@localhost ~]# docker network connect mynet tomcat01
# 连通之后,就是将tomcat01放到了mynet网络下
# 一个容器,两个ip地址     阿里云服务:公网ip,私网ip
bash 复制代码
# tomcat01可以打通tomcat-net-01
[root@localhost ~]# docker exec -it tomcat01 curl tomcat-net-01:8080
<!doctype html><html lang="en"><head><title>HTTP Status 404 -- Not Found</title><style type="text/css">body {font-family:Tahoma,Arial,sans-serif;} h1, h2, h3, b {color:white;background-color:#525D76;} h1 {font-size:22px;} h2 {font-size:16px;} h3 {font-size:14px;} p {font-size:12px;} a {color:black;} .line {height:1px;background-color:#525D76;border:none;}</style></head><body><h1>HTTP Status 404 -- Not Found</h1><hr class="line" /><p><b>Type</b> Status Report</p><p><b>Description</b> The origin server did not find a current representation for the target resource or is not willing to disclose that one exists.</p><hr class="line" /><h3>Apache Tomcat/10.0.14</h3></body></html>

结论:假设要跨网络操作别人,就需要使用docker network connect连通


10. 部署Redis集群实战

启动六个容器,三主三从(分片+高可用+负载均衡)

bash 复制代码
# 创建网卡
docker network create redis --subnet 172.38.0.0/16
# 通过脚本创建六个redis配置
for port in $(seq 1 6); \
do \
mkdir -p /mydata/redis/node-${port}/conf
touch /mydata/redis/node-${port}/conf/redis.conf
cat << EOF >/mydata/redis/node-${port}/conf/redis.conf
port 6379
bind 0.0.0.0
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
cluster-announce-ip 172.38.0.1${port}
cluster-announce-port 6379
cluster-announce-bus-port 16379
appendonly yes
EOF
done
# 启动
docker run -p 6371:6379 -p 16371:16379 --name redis-1 \
-v /mydata/reids/node-1/data:/data \
-v /mydata/redis/node-1/conf/redis.conf:/etc/redis/redis.conf \
-d --net redis --ip 172.38.0.11 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
docker run -p 6372:6379 -p 16372:16379 --name redis-2 \
-v /mydata/reids/node-2/data:/data \
-v /mydata/redis/node-2/conf/redis.conf:/etc/redis/redis.conf \
-d --net redis --ip 172.38.0.12 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
docker run -p 6373:6379 -p 16373:16379 --name redis-3 \
-v /mydata/reids/node-3/data:/data \
-v /mydata/redis/node-3/conf/redis.conf:/etc/redis/redis.conf \
-d --net redis --ip 172.38.0.13 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
docker run -p 6374:6379 -p 16374:16379 --name redis-4 \
-v /mydata/reids/node-4/data:/data \
-v /mydata/redis/node-4/conf/redis.conf:/etc/redis/redis.conf \
-d --net redis --ip 172.38.0.14 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
docker run -p 6375:6379 -p 16375:16379 --name redis-5 \
-v /mydata/reids/node-5/data:/data \
-v /mydata/redis/node-5/conf/redis.conf:/etc/redis/redis.conf \
-d --net redis --ip 172.38.0.15 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
docker run -p 6376:6379 -p 16376:16379 --name redis-6 \
-v /mydata/reids/node-6/data:/data \
-v /mydata/redis/node-6/conf/redis.conf:/etc/redis/redis.conf \
-d --net redis --ip 172.38.0.16 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
[root@localhost conf]# docker exec -it redis-1 /bin/sh
/data # ls
appendonly.aof  nodes.conf
# 创建集群
/data # redis-cli --cluster create 172.38.0.11:6379 172.38.0.12:6379 172.38.0.13
:6379 172.38.0.14:6379 172.38.0.15:6379 172.38.0.16:6379 --cluster-replicas 1
>>> Performing hash slots allocation on 6 nodes...
Master[0] -> Slots 0 - 5460
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
Adding replica 172.38.0.15:6379 to 172.38.0.11:6379
Adding replica 172.38.0.16:6379 to 172.38.0.12:6379
Adding replica 172.38.0.14:6379 to 172.38.0.13:6379
M: 0c97073d209ffccedb055c68f2dbe8c481a77504 172.38.0.11:6379
   slots:[0-5460] (5461 slots) master
M: 84d8d25a96ba851ba8b4fe54a925255b415ad4bc 172.38.0.12:6379
   slots:[5461-10922] (5462 slots) master
M: 3dfbd972115d98be889adca20199f9d7c5c5577a 172.38.0.13:6379
   slots:[10923-16383] (5461 slots) master
S: 6101466ee56f010b223e9495963e724b59c6a435 172.38.0.14:6379
   replicates 3dfbd972115d98be889adca20199f9d7c5c5577a
S: 47895310a5642cb566b03450ffe8e23b12b5d3bf 172.38.0.15:6379
   replicates 0c97073d209ffccedb055c68f2dbe8c481a77504
S: 968211de1981e640d8a194e0700ac856dc88a6d0 172.38.0.16:6379
   replicates 84d8d25a96ba851ba8b4fe54a925255b415ad4bc
Can I set the above configuration? (type 'yes' to accept): yes
>>> Nodes configuration updated
>>> Assign a different config epoch to each node
>>> Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join
...
>>> Performing Cluster Check (using node 172.38.0.11:6379)
M: 0c97073d209ffccedb055c68f2dbe8c481a77504 172.38.0.11:6379
   slots:[0-5460] (5461 slots) master
   1 additional replica(s)
S: 968211de1981e640d8a194e0700ac856dc88a6d0 172.38.0.16:6379
   slots: (0 slots) slave
   replicates 84d8d25a96ba851ba8b4fe54a925255b415ad4bc
M: 3dfbd972115d98be889adca20199f9d7c5c5577a 172.38.0.13:6379
   slots:[10923-16383] (5461 slots) master
   1 additional replica(s)
M: 84d8d25a96ba851ba8b4fe54a925255b415ad4bc 172.38.0.12:6379
   slots:[5461-10922] (5462 slots) master
   1 additional replica(s)
S: 6101466ee56f010b223e9495963e724b59c6a435 172.38.0.14:6379
   slots: (0 slots) slave
   replicates 3dfbd972115d98be889adca20199f9d7c5c5577a
S: 47895310a5642cb566b03450ffe8e23b12b5d3bf 172.38.0.15:6379
   slots: (0 slots) slave
   replicates 0c97073d209ffccedb055c68f2dbe8c481a77504
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

Docker搭建Redis集群完成!

bash 复制代码
# 进入集群
/data # redis-cli -c
# 查看集群信息
127.0.0.1:6379> cluster info
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:3
cluster_current_epoch:6
cluster_my_epoch:1
cluster_stats_messages_ping_sent:1643
cluster_stats_messages_pong_sent:1604
cluster_stats_messages_sent:3247
cluster_stats_messages_ping_received:1599
cluster_stats_messages_pong_received:1643
cluster_stats_messages_meet_received:5
cluster_stats_messages_received:3247
# 查看集群节点-->redis-3是主节点,redis-4是从节点
127.0.0.1:6379> cluster nodes
968211de1981e640d8a194e0700ac856dc88a6d0 172.38.0.16:6379@16379 slave 84d8d25a96ba851ba8b4fe54a925255b415ad4bc 0 1639727967684 6 connected
0c97073d209ffccedb055c68f2dbe8c481a77504 172.38.0.11:6379@16379 myself,master - 0 1639727967000 1 connected 0-5460
3dfbd972115d98be889adca20199f9d7c5c5577a 172.38.0.13:6379@16379 master - 0 1639727968501 3 connected 10923-16383
84d8d25a96ba851ba8b4fe54a925255b415ad4bc 172.38.0.12:6379@16379 master - 0 1639727968707 2 connected 5461-10922
6101466ee56f010b223e9495963e724b59c6a435 172.38.0.14:6379@16379 slave 3dfbd972115d98be889adca20199f9d7c5c5577a 0 1639727968707 4 connected
47895310a5642cb566b03450ffe8e23b12b5d3bf 172.38.0.15:6379@16379 slave 0c97073d209ffccedb055c68f2dbe8c481a77504 0 1639727967000 5 connected
# 存储值-->存在redis-3里
127.0.0.1:6379> set a b
-> Redirected to slot [15495] located at 172.38.0.13:6379
OK
# 停掉172.38.0.13
[root@localhost ~]# docker stop redis-3
redis-3
# 关闭集群
Ctrl+C
# 重新启动集群
/data # redis-cli -c
# 获取值-->在redis-4中
127.0.0.1:6379> get a
-> Redirected to slot [15495] located at 172.38.0.14:6379
"b"
# 查看节点-->redis-3停掉了,redis-4变成了主节点
172.38.0.14:6379> cluster nodes
3dfbd972115d98be889adca20199f9d7c5c5577a 172.38.0.13:6379@16379 master,fail - 1639735747538 1639735745000 3 connected
47895310a5642cb566b03450ffe8e23b12b5d3bf 172.38.0.15:6379@16379 slave 0c97073d209ffccedb055c68f2dbe8c481a77504 0 1639735859000 5 connected
968211de1981e640d8a194e0700ac856dc88a6d0 172.38.0.16:6379@16379 slave 84d8d25a96ba851ba8b4fe54a925255b415ad4bc 0 1639735860000 6 connected
84d8d25a96ba851ba8b4fe54a925255b415ad4bc 172.38.0.12:6379@16379 master - 0 1639735859000 2 connected 5461-10922
6101466ee56f010b223e9495963e724b59c6a435 172.38.0.14:6379@16379 myself,master - 0 1639735858000 7 connected 10923-16383
0c97073d209ffccedb055c68f2dbe8c481a77504 172.38.0.11:6379@16379 master - 0 1639735859579 1 connected 0-5460
# 退出
172.38.0.14:6379> exit
/data # exit
[root@localhost conf]# clear
[root@localhost conf]# docker rm -f $(docker ps -aq)
3ca0ed7155f6
9aaa81b6a46c
80cf12d69a3c
464f19f93ac4
3d7e55508b14
8a9e49712cc9

使用了Docker之后,所有的技术都会慢慢变得简单起来。


11. SpringBoot微服务打包Docker镜像

1、构建SpringBoot项目

2、打包应用

3、编写dockerfile

bash 复制代码
FROM java:8
COPY *.jar /app.jar
CMD ["--server.port=8080"]
EXPOSE 8080
ENTRYPOINT ["java","-jar","/app.jar"]

4、构建镜像

bash 复制代码
[root@localhost conf]# cd /home
[root@localhost home]# ls
ceshi  dockerfile  docker-test-volume  mysql  Packages  tomcat
[root@localhost home]# mkdir idea
[root@localhost home]# cd idea
[root@localhost idea]# ls
[root@localhost idea]# ls
Docker-0.0.1-SNAPSHOT.jar  Dockerfile
[root@localhost idea]# docker build -t idea666 .
Sending build context to Docker daemon  17.56MB
Step 1/5 : FROM java:8
8: Pulling from library/java
5040bd298390: Pull complete 
fce5728aad85: Pull complete 
76610ec20bf5: Pull complete 
60170fec2151: Pull complete 
e98f73de8f0d: Pull complete 
11f7af24ed9c: Pull complete 
49e2d6393f32: Pull complete 
bb9cdec9c7f3: Pull complete 
Digest: sha256:c1ff613e8ba25833d2e1940da0940c3824f03f802c449f3d1815a66b7f8c0e9d
Status: Downloaded newer image for java:8
 ---> d23bdf5b1b1b
Step 2/5 : COPY *.jar /app.jar
 ---> 6d10e7a0a488
Step 3/5 : CMD ["--server.port=8080"]
 ---> Running in d25c16614512
Removing intermediate container d25c16614512
 ---> 56d94e2cba98
Step 4/5 : EXPOSE 8080
 ---> Running in a5682ef63fd1
Removing intermediate container a5682ef63fd1
 ---> 635c54c90069
Step 5/5 : ENTRYPOINT ["java","-jar","/app.jar"]
 ---> Running in 43739bc53e3e
Removing intermediate container 43739bc53e3e
 ---> 73188d20cb6c
Successfully built 73188d20cb6c
Successfully tagged idea666:latest

5、发布运行

bash 复制代码
[root@localhost idea]# docker run -d -P --name idea-springboot-web idea666
972a723ab17766b87cd8f0199db61c0494f5a5a3cfffd4a6b4a50c94dd064eab
[root@localhost idea]# docker ps
CONTAINER ID   IMAGE     COMMAND                  CREATED          STATUS          PORTS                                         NAMES
972a723ab177   idea666   "java -jar /app.jar ..."   12 seconds ago   Up 10 seconds   0.0.0.0:49165->8080/tcp, :::49165->8080/tcp   idea-springboot-web
# 访问49165->8080
[root@localhost idea]# curl localhost:49165/hello
Hello,Controller!

以后我们使用了Docker之后,给别人交付的就是一个镜像即可!

相关推荐
玄武 剑15 分钟前
开源自动化热键映射工具autohotkey十大用法及精选脚本
运维·自动化
登云时刻16 分钟前
【问题记录】Jenkins Pipeline读取变量的各种方法
运维·jenkins
weishenjieneng19 分钟前
微深节能 煤码头自动化翻堆及取料集控系统 格雷母线
运维·自动化
威斯盾科技25 分钟前
电力设备巡检管理系统
运维·网络·信息可视化
zhishengwangxiao29 分钟前
职升网:一级计量师证书含金量有多少?
运维·服务器
科学的发展-只不过是读大自然写的代码39 分钟前
ubuntu 进入命令行
linux·运维·ubuntu
念晚91743 分钟前
Linux——测网速例子,在网站查看生成的图片
linux·运维·服务器·网络·数据库
运维Linux和python1 小时前
从nginx返回404来看http1.0和http1.1的区别
运维·nginx
bestcxx1 小时前
(九)Docker 的网络通信
docker·容器
孤城2861 小时前
10 docker 安装 mysql详解
mysql·docker·微服务·容器