Docker容器

image-20210218205343872

1、Docker概述

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

文档:https://docs.docker.com/get-started/overview/

image-20210218211334994

仓库地址:https://hub.docker.com/

为什么会出现

之前开发一款产品:

  • 开发–上线,两套环境!应用环境!应用配置!
  • 问题:我在我的电脑上可以运行,换个环境却不行!版本更新,导致服务不可用!
  • 环境配置十分麻烦,每一个机器都要部署环境(集群Redis、ES、Hadoop……)
  • 发布一个项目jar(需要部署Redis、MySQL、jdk、ES)
  • 之前在服务器配置应用环境,配置麻烦,不能跨平台
  • 开发做jar,运维配置环境!

现在:

  • 项目带上环境安装打包
  • 开发打包部署上线,一套流程做完
  • java – apk – 发布(应用商店) – 下载安装即可用
  • java – jar(环境) – 打包项目带上环境(镜像) – Docker仓库:商店 – 下载我们发布的镜像 – 直接运行即可

Docker给以上问题,提供了解决方案!

Docker的思想就来自于集装箱!

之前:Jre – 多个应用(端口冲突) – 原来是交叉的!

隔离:Docker核心思想!打包装箱!每个箱子相互隔离!

Docker通过隔离机制,可以将服务器利用到极致!

Docker的优势

虚拟机:在window中安装一个VMware,通过这个软件我们可以虚拟出一台或者多台电脑!但是笨重!

虚拟机也属于虚拟化技术,但是占用内存大!

Docker:隔离,镜像(最核心的环境 + jdk + mysql)十分小巧,运行镜像就可以,几个M或者KB,秒级启动!

Docker 基于Go语言开发!开源项目!

Docker能干嘛

之前的虚拟机技术

image-20210218220035693

缺点:

  1. 资源占用多
  2. 冗余步骤多
  3. 启动很慢

容器化技术

容器化技术不是模拟的一个完整的操作系统

image-20210218220826134

比较Docker 和 虚拟机技术的不同:

  • 传统虚拟机,虚拟一条硬件,运行一个完整的操作系统,然后在这个系统上安装和运行软件
  • 容器中的应用直接运行在 宿主机 的内容,容器时没有自己的内核的,也没有虚拟我们的硬件,所以就轻便了
  • 每个容器间时相互隔离的,每个容器内都有一个属于自己的文件系统,互不影响

DevOps(开发、运维)

应用更快速的交付和部署

  • 传统:一堆帮助文档,安装程序
  • Docker:打包镜像发布测试,一键运行

更便捷的升级和扩缩容

  • 使用了Docker之后,我们部署应用就和搭积木一样
  • 项目打包为镜像,扩展 只需要在另一个服务器中一键运行

更简单的系统运维

  • 在容器化之后,我们的开发,测试环境都是高度一致的

更高效的计算资源利用

  • 可以将服务器的性能应用到极致
  • Docker 是内核级别的虚拟化,可以在一个物理机上运行很多的容器实例

2、Docker安装

Docker的基本组成

image-20210221110739417

镜像(image):

  • docker镜像就好比是一个模板,可以通过这个模板来创建容器服务,通过这个镜像可以创建多个容器(最终服务运行或者项目运行就是在容器中的)

容器(container):

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

仓库(repository):

  • 仓库就是存放镜像的地方!
  • 仓库分为共有仓库和私有仓库!
  • Docker Hub(默认是国外的)
  • 阿里云…都有容器服务(配置镜像加速)

安装Docker

环境准备

  1. 需要Linux基础
  2. CentOS 7
  3. 使用Xshell连接远程服务器

环境查看

# 查看系统内核版本,需要3.10以上
[root@iz2ze2js0u6m077omgcbzmz /]# uname -r
3.10.0-1127.19.1.el7.x86_64
# 系统配置
[root@iz2ze2js0u6m077omgcbzmz /]# 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"

安装

帮助文档:https://docs.docker.com/get-docker/

需要选择Linux系统的版本

image-20210221111649221

然后选择CentOS版本

image-20210221111759852

步骤:

# 1、卸载旧的版本
yum remove docker \
                  docker-client \
                  docker-client-latest \
                  docker-common \
                  docker-latest \
                  docker-latest-logrotate \
                  docker-logrotate \
                  docker-engine

# 2、需要的安装包
yum install -y yum-utils

# 3、设置镜像的仓库
yum-config-manager \
    --add-repo \
    https://download.docker.com/linux/centos/docker-ce.repo    # 默认是从国外的(太慢,不建议)


yum-config-manager \
    --add-repo \
    http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo # 推荐使用阿里云的

# 4、更新软件包索引
yum makecache fast

# 5、安装docker相关的内容,docker-ce 社区版,ee 企业版
yum install docker-ce docker-ce-cli containerd.io

# 6、启动docker
systemctl start docker

# 7、查看是否安装成功
docker version

image-20210221113029255

# 8、使用run启动hello-word镜像
docker run hello-world

image-20210221113237929

# 9、查看一下下载的hello-world镜像是否存在
[root@iz2ze2js0u6m077omgcbzmz /]# docker images
REPOSITORY    TAG       IMAGE ID       CREATED         SIZE
hello-world   latest    bf756fb1ae65   13 months ago   13.3kB

卸载docker:

# 1、卸载依赖
yum remove docker-ce docker-ce-cli containerd.io

# 2、删除资源
rm -rf /var/lib/docker    # docker的默认工作路径

阿里云镜像加速

1、访问阿里云控制台,找到容器镜像服务

image-20210221113956329

2、点击开通,设置仓库登录密码即可

image-20210221114030975

3、找到镜像加速地址

image-20210221114219761

4、配置使用

# 创建目录
sudo mkdir -p /etc/docker

# 编写配置文件
sudo tee /etc/docker/daemon.json <<-'EOF'
{ 
  "registry-mirrors": ["https://keywishf.mirror.aliyuncs.com"]
} 
EOF

# 服务重启
sudo systemctl daemon-reload

# 启动doceker
sudo systemctl restart docker

回顾HelloWord流程

image-20210221114717793

底层原理

Docker是怎么工作的?

  • Docker 是一个 client - Server 结构的系统,Docker的守护进程运行在主机上,通过Socket从客户端访问!
  • DockerServer 接收到 Docker-client 的指令,就会执行这个命令!

image-20210221115243553

Docker为什么比 VM(虚拟机)快?

  1. Docker有着比虚拟机更少的抽象层
  2. Docker利用的是宿主机的内核,vm需要的是 Guest OS

image-20210221115359405

所以说,新建一个容器的时候,docker不需要像虚拟机一样重新加载一个操作系统内核,避免引导。虚拟机加载 Guest OS,分钟级别的,而docker 是利用 宿主机的操作系统,省略了这个复杂的过程,秒级启动!

image-20210221115710693

3、Docker的常用命令

帮助命令

docker version        # 像是docker的版本信息
docker info            # docker系统信息,包括镜像和容器的数量
docker 命令 --help   # 帮助命令

帮助文档地址:https://docs.docker.com/reference/

image-20210221120152725

镜像的命令

docker images :查看本地所有镜像

# 查看镜像
[root@iz2ze2js0u6m077omgcbzmz /]# docker images
REPOSITORY    TAG       IMAGE ID       CREATED         SIZE
hello-world   latest    bf756fb1ae65   13 months ago   13.3kB

# 解释
REPOSITORY    镜像的仓库源
TAG            镜像的标签
IMAGE ID    镜像的id
CREATED        镜像的创建时间
SIZE        镜像的大小

# 常用的可选项
  -a, --all             # 列出所有的镜像
  -q, --quiet           # 只显示镜像的id

Docker search 搜索镜像

可以直接在官网搜索镜像:https://hub.docker.com/

image-20210221132848506

image-20210221135305077

使用命令的方式:

[root@iz2ze2js0u6m077omgcbzmz /]# docker search mysql
NAME        DESCRIPTION           STARS     OFFICIAL   AUTOMATED
mysql       MySQL is a widely used, open-source relation…   10530     [OK]       
mariadb     MariaDB is a community-developed fork of MyS…   3934      [OK]

# 可选项,通过收藏数来过滤(大于3000)
docker search mysql --filter=STARS=3000

docker pull 镜像下载

# 下载镜像 docker pull 镜像名[:tag]
[root@iz2ze2js0u6m077omgcbzmz /]# docker pull mysql
Using default tag: latest    # 不写tag,就默认下载最新版
latest: Pulling from library/mysql
a076a628af6f: Pull complete # 分层下载,docker images的核心,联合文件系统
f6c208f3f991: Pull complete 
88a9455a9165: Pull complete 
406c9b8427c6: Pull complete 
7c88599c0b25: Pull complete 
25b5c6debdaf: Pull complete 
43a5816f1617: Pull complete 
1a8c919e89bf: Pull complete 
9f3cf4bd1a07: Pull complete 
80539cea118d: Pull complete 
201b3cad54ce: Pull complete 
944ba37e1c06: Pull complete 
Digest: sha256:feada149cb8ff54eade1336da7c1d080c4a1c7ed82b5e320efb5beebed85ae8c    # 签名
Status: Downloaded newer image for mysql:latest
docker.io/library/mysql:latest    # 真实地址

选择版本下载,必须对应官网中现有的版本

image-20210221140220409

[root@iz2ze2js0u6m077omgcbzmz /]# docker pull mysql:5.7
5.7: Pulling from library/mysql
a076a628af6f: Already exists # 不会重复下载现有东西
f6c208f3f991: Already exists 
88a9455a9165: Already exists 
406c9b8427c6: Already exists 
7c88599c0b25: Already exists 
25b5c6debdaf: Already exists 
43a5816f1617: Already exists 
1831ac1245f4: Pull complete 
37677b8c1f79: Pull complete 
27e4ac3b0f6e: Pull complete 
7227baa8c445: Pull complete 
Digest: sha256:b3d1eff023f698cd433695c9506171f0d08a8f92a0c8063c1a4d9db9a55808df
Status: Downloaded newer image for mysql:5.7
docker.io/library/mysql:5.7

image-20210221140501929

docker rmi 删除镜像(通过id删除)

# 删除单个镜像
docker rmi -f 镜像id

# 删除多个镜像
docker rmi -f 镜像id 镜像id 镜像id 

# 删除全部镜像
docker rmi -f $(docker images -qp)    # -qp 是查询所有的id

image-20210221140659054

容器命令

说明:我们有了镜像才可以创建容器,Linux

docker pull centos

新建容器并启动

docker run [可选参数] image

# 参数说明
--name="Name"    # 容器名字 tomcat01 tomcat 02, 用来区分容器
-d                # 后台方式运行
-it             # 使用交互方式运行,进入容器查看内容
-p                # 指定容器的端口 -p 8080:8080
    -p ip:主机端口:容器端口
    -p 主机端口:容器端口
    -p 容器端口
-P                # 随机指定端口(大写P)

启动并进入容器

# 使用-it交互模式,不然无法进入
[root@iz2ze2js0u6m077omgcbzmz /]# docker run -it centos /bin/bash

# 启动之后,发现主机名变化
# 查看的是容器内的centos文件
[root@afe08a58288f /]# ls
bin  etc   lib      lost+found  mnt  proc  run   srv  tmp  var
dev  home  lib64  media       opt  root  sbin  sys  usr

# 从容器中退回主机
[root@afe08a58288f /]# exit

image-20210221142525271

列出所有在运行的容器

  • -a :列出当前正在运行的容器 + 历史运行过的容器
  • -n=? :显示最近创建的容器
  • -q :只显示容器的编号
# 查看正在运行的容器,为空
[root@iz2ze2js0u6m077omgcbzmz /]# docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES

# 查看曾经运行的容器
[root@iz2ze2js0u6m077omgcbzmz /]# docker ps -a
CONTAINER ID   IMAGE          COMMAND       CREATED         STATUS                          PORTS     NAMES
afe08a58288f   centos         "/bin/bash"   3 minutes ago   Exited (0) About a minute ago             reverent_goldwasser
b4520ec7f5c1   bf756fb1ae65   "/hello"      3 hours ago     Exited (0) 3 hours ago                    youthful_margulis

退出容器

exit    # 直接容器停止并退出
Ctrl + p + Q    # 容器不停止退出

删除容器

# 删除指定的容器,不能删除正在运行的容器,如果要强制删除 rm -f
docker rm 容器id    

# 删除所有的容器
docker rm -f $(docker ps -aq)

# 删除所有的容器
docker ps -a -q|xargs docker rm

启动和停止容器的操作

# 启动容器(对于启动之后停止的容器)
docker start 容器id

# 重启容器
docker restart 容器id

# 停止容器
docker stop 容器id

# 杀掉容器
docker kill 容器id

image-20210221144028836

常用的其他命令

后台启动容器

# 命令 docker run -d 镜像名
docker run -d centos

# 问题:执行docker ps 发现 centos 停止了

# 常见的坑:docker 容器使用后台运行,就必须要有一个前台进程,docker发现没有应用就会自动停止
# nginx,容器启动后,发现自己没有提供服务,就会立刻停止,就是没有程序了
# 添加脚本启动
[root@iz2ze2js0u6m077omgcbzmz /]# docker run -d centos /bin/sh -c "while true;do echo helloworld;sleep 1;done"
5d09f7ecc0c2a3dddcb118607728baceceed3a0a1a36449432d7e96426055562

# 查看是否在运行
[root@iz2ze2js0u6m077omgcbzmz /]# docker ps
CONTAINER ID   IMAGE     COMMAND                  CREATED         STATUS         PORTS     NAMES
5d09f7ecc0c2   centos    "/bin/sh -c 'while t…"   4 seconds ago   Up 3 seconds             admiring_turing

查看日志

docker logs -f -t --tail [条数] [容器id]

# 编写一段shell脚本
docker run -d centos /bin/sh -c "while true;do echo helloworld;sleep 1;done"

# 查看对应的日志,并不断追踪
-f # 日志带上时间戳
-t # 显示所有日志
[root@iz2ze2js0u6m077omgcbzmz /]# docker logs -f -t --tail 10 5d09f7ecc0c2

image-20210222194426678

查看容器的进程信息

# 命令:docker top 容器id(杀进程通过ppid)
[root@iz2ze2js0u6m077omgcbzmz /]# docker top 5d09f7ecc0c2
UID   PID    PPID      C      STIME    TTY        TIME         CMD
root   785   733       0      19:40    ?          00:00:00     /bin/sh -c while true;do echo helloworld;sleep 1;done

root   2081  785       0      19:46    ?          00:00:00    /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 1

查看镜像的元数据

# 命令: docker inspect 容器id
[root@iz2ze2js0u6m077omgcbzmz /]# docker inspect 5d09f7ecc0c2

image-20210222195239209

进入当前正在运行的容器

# 我们通常的容器都是使用后台方式进行,需要进入容器修改一些配置

# 方式一:docker exec -it 容器id /bin/bash
# 进入容器后开启一个新的终端,可以在里面操作()常用

# 测试
[root@iz2ze2js0u6m077omgcbzmz /]# docker ps
CONTAINER ID   IMAGE     COMMAND                  CREATED             STATUS             PORTS     NAMES
5d09f7ecc0c2   centos    "/bin/sh -c 'while t…"   About an hour ago   Up About an hour             admiring_turing
[root@iz2ze2js0u6m077omgcbzmz /]# docker exec -it 5d09f7ecc0c2 /bin/bash
[root@5d09f7ecc0c2 /]# ls 
bin  etc   lib      lost+found  mnt  proc  run   srv  tmp  var
dev  home  lib64  media       opt  root  sbin  sys  usr
# 方式二:docker attach 容器id
# 进入容器正在执行的终端,不会启动新的进程

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

docker cp 容器id:容器内路径 目的主机路径

测试

# 查看当前主机目录下
[root@iz2ze2js0u6m077omgcbzmz home]# ls
dst  epel-release-6-8.noarch.rpm  redis  www
[root@iz2ze2js0u6m077omgcbzmz home]# docker ps
CONTAINER ID   IMAGE     COMMAND                  CREATED             STATUS             PORTS     NAMES
5d09f7ecc0c2   centos    "/bin/sh -c 'while t…"   About an hour ago   Up About an hour             admiring_turing

# 进入docker容器内部
[root@iz2ze2js0u6m077omgcbzmz home]# docker exec -it 5d09f7ecc0c2 /bin/bash
[root@5d09f7ecc0c2 /]# cd home
[root@5d09f7ecc0c2 home]# ls
# 在容器中新建一个文件
[root@5d09f7ecc0c2 home]# touch test.java
# 退出容器
[root@5d09f7ecc0c2 home]# exit
exit

# 将这个文件拷贝出来到主机上
[root@iz2ze2js0u6m077omgcbzmz home]# docker cp 5d09f7ecc0c2:/home/test.java /home
[root@iz2ze2js0u6m077omgcbzmz home]# ls
dst  epel-release-6-8.noarch.rpm  redis  test.java  www

# 拷贝是一个手动过程,以后可以使用 -v 卷的技术,可以实现自动同步

小结

image-20210222211347895

4、安装Nginx

# 1、搜索镜像(在官网中搜索才可以看到版本信息和文档)
docker search nginx

# 2、下载镜像
docker pull nginx

# 3、启动nginx
# -d 后台运行
# --name 给容器命名
# -p 宿主机端口:容器内部端口
docker run -d --name nginx01 -p 3344:80 nginx

# 4、测试访问端口
curl localhost:8000

# 5、停止nginx服务,停止之后就访问不了
docker stop 容器id/nginx01

image-20210222213515808

端口暴露原理:相当于主机的3344端口映射到docker中的80端口

image-20210222213117135

思考:我们每次要改动nginx的配置文件都需要进入容器内容,十分麻烦,是否可以在容器外部提供一个映射路径,达到在容器修改文件,容器内部就可以自动修改?

使用 -v 数据卷可以实现!

5、安装Tomcat

# 官方的使用
docker run -it --rm tomcat:9.0

# 我们之前的启动都是后台,停止容器之后,容器还是可以查到
# docker run -it --rm 一般用来测试,用完即删

# 1、下载启动
docker pull tomcat:9.0

# 2、启动运行
docker run -d -p 9000:8080 --name tomcat01 tomcat

通过外网访问9000端口

image-20210224114525865

分析出现404原因

# 进入容器
docker exec -it tomcat01 /bin/bash

# 发现问题:1、linux命令少了,2、没有webapps
# 原因:阿里云镜像默认是最小的镜像,所有不必要的都剔除掉
# 保证最小可运行环境

思考:以后要部署项目,每次都要进入容器是不是十分麻烦?要是可以在容器外部提供一个映射路径,webapps我们可以在外部放置项目,就自动同步内部就好了!

6、部署 ES + Kibana

# es 暴露的端口很多
# es 十分的耗内存 1.x G
# es 的数据一般需要放置到安全目录!挂载
# --net somenetwork 为网络配置,暂时不用

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

# 启动了之后 linux 就会卡住了! docker stats 查看cpu状态

# 查看 docker stats

# 测试以下es是否成功了
curl localhost:9200

# 赶紧关闭,增加内容的限制
docker stop 容器id

image-20210224120856019

修改配置文件 -e 环境配置修改

# 修改配置文件,限制使用的内容
docker run -d --name elasticsearch02 -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node"  -e ES_JAVA_OPTS="-Xms64m -Xmx512m" elasticsearch:7.6.2

# 查看docker stats
docker stats 容器id

image-20210224120905711

使用kibana连接ES

思考网络如何连接过去

image-20210224121140385

7、可视化

portainer(先用这个)

docker run -d -p 8088:9000 \
--restart=always -v "/var/run/docker.sock:/var/run/docker.sock" --privileged=true portainer/portainer

Rancher(CI/CD再用)

什么是 portainer?

Docker图形化界面管理工具!提供一个后台面板供我们操作!

# 下载portainer
docker run -d -p 8088:9000 \
--restart=always -v "/var/run/docker.sock:/var/run/docker.sock" --privileged=true portainer/portainer

访问测试:外网8088

image-20210224125709788

首次加载比较久,设置用户名密码之后进入

image-20210224130039423

选择使用本地仓库

image-20210224130152827

连接进入

image-20210224130838730

这里可以查看所有的镜像和容器

image-20210224130930288

8、Docker镜像讲解

镜像是什么?

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

所有的应用,直接打包成为docker镜像,就可以直接跑起来!

如何得到镜像:

  • 从远程仓库下载
  • 朋友拷贝给你
  • 自己制作一个镜像 DockerFile

Docker镜像加载原理

UnionFS(联合文件系统)

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

例如:

# 安装docker   第一层
# 安装centos     第二层
# 安装JDK         第三层

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

Docker镜像加载原理

docker的镜像实际上由一层一层的文件系统组成,这种层级的文件系统UnionFS。

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

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

image-20210224141840002

平时我们安装进虚拟机的Centos都是好几个G,为什么Docker这里才200M?

image-20210224141943651

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

分层原理

分层的镜像

我们可以去下载一个镜像,注意观察下载的日志输出,可以看到是一层一层的下载!

image-20210313095405902

思考:为什么docker镜像要采用这种分层的结构呢?

最大的好处,莫过于资源共享了!比如有多个镜像都从相同的Base镜像构建而来,那么宿主机只需要在磁盘上保留一份base镜像,同时内存中也只需要加载一份base镜像,这样就可以为所有的容器服务了,而且镜像的每一层都可以被共享!

查看镜像封层的方式可以通过 docker image inspect 命令

[root@iz2ze2js0u6m077omgcbzmz ~]# docker image inspect redis:latest

image-20210313095817664

理解:

所有的Docker 镜像都始于一个基础镜像层,当进行修改或增加新的内容时,就会在当前镜像层之上,创建新的镜像层。

举一个简单的例子,例如基于 Ubuntu Linux 16.04 创建一个新的镜像,这就是新镜像的第一层;如果在这个镜像中添加 Python 包,就会在基础镜像层之上创建第二个镜像层;如果继续添加一个安全补丁,就会创建第三个镜像层。

该镜像当前已经包含3个镜像层,如下图所示(简单的例子)

image-20210313100226470

在添加额外的镜像层的同时,镜像始终保持是当前所有镜像的组合。如下图,每个镜像层包含3个文件,而镜像包含了来自两个镜像层的6个文件。

image-20210313100636010

上图中的镜像层跟之前图中的略有区别,主要目的是便于展示文件。

下图中展示了一个稍微复杂的三层镜像,在外部看来整个镜像只有6个文件,这是因为最上层的文件7 是文件5的一个更新版本(可以覆盖文件5)。

image-20210313100828231

在这种情况下,上层镜像层中的文件覆盖了底层镜像层中的文件。这样就使得文件的更新版本作为一个新镜像层添加到镜像当中。

Docker 通过存储引擎(新版本采用快照机制)的方式来实现镜像层堆栈,并保证多镜像层对外展示为统一的文件系统。

Linux 上可用的存储引擎有 AUFS、Overlay2、Device Mapper、Btrfs 以及 ZFS。顾名思义,每种存储引擎都基于Linux中对应的文件系统或者块设备技术,并且每种存储引擎都有其独有的性能特点。

Docker 在 Windows 上仅支持 windowsfilter 一种存储引擎,该引擎基于NTFS 文件系统之上实现了分层和 Cow。

下图展示了与系统显示相同的三层镜像。所有镜像层堆叠并合并,对外提供统一的视图。

image-20210313101426464

特点

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

这一层就是我们通常说的容器层,容器之下的都叫镜像层(无法改变)!

image-20210313102020837

完整过程:

image-20210313102242966

9、commit容器

提交镜像

docker commit 提交容器成为一个新的副本

# 命令和 git 原理类似
docker commit -m="提交的描述信息" -a="作者" 容器id 目标镜像名:[TAG]

实战测试

# 1、启动一个默认的tomcat
[root@iz2ze2js0u6m077omgcbzmz ~]# docker run -it -p 9000:8080 tomcat

# 2、发现这个默认的 tomcat 是没有webapps应用。这是镜像的原因,官方的镜像默认 webapps下面是没有文件的!
[root@iz2ze2js0u6m077omgcbzmz ~]# docker exec -it fc6993915d41 /bin/bash

# 3、自行拷贝进去了基本文件
root@fc6993915d41:/usr/local/tomcat# cp -r webapps.dist/* webapps
root@fc6993915d41:/usr/local/tomcat# cd webapps
root@fc6993915d41:/usr/local/tomcat/webapps# ls
ROOT  docs  examples  host-manager  manager

修改之后就可以看到正常的tomcat页面了

image-20210313104046775

# 4、将我们操作过的容器通过 commit 提交为一个镜像!我们以后就使用修改过的镜像即可,自定义为tomcat02,版本为1.0
[root@iz2ze2js0u6m077omgcbzmz ~]# docker commit -a="xiaojiang" -m="add webapps app" fc6993915d41 tomcat02:1.0

image-20210313104432119

如果想要保存当前容器的状态,就可以通过commit 来提交,获得一个镜像,就好比我们以前学习VM时候使用的快照。

10、容器数据卷

什么是容器数据卷

docker的理论回顾

将应用和环境打包成一个镜像!

数据?如果数据都在容器中,那么我们容器删除,数据就会丢失!需求:数据可以持久化

MySQL,容器删了,数据也没了!需求:MySQL数据可以存储在本地!

容器之间可以有一个数据共享技术!Docker容器中产生的数据,同步到本地!

这就是卷技术!目录的挂载,将我们容器内的目录,挂载到Linux上面!

image-20210313105411779

总结:容器的持久化和同步操作!容器间也可以数据共享!

使用数据卷

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

# 就好比端口映射
docker run -it -v 主机目录:容器内目录

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

# 启动起来之后我们可以通过 docker inspect 容器id (进行查看)
docker inspect bb59516980a9

image-20210320163453833

测试文件的同步

image-20210320163735466

测试:停止容器之后修改文件

  1. 停止容器
  2. 宿主机上修改文件
  3. 启动容器
  4. 容器内的数据内容依然存在

image-20210320164253752

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

实战:安装MySQL

思考:MySQL 的数据持久化问题!

# 获取镜像
docker pull mysql:5.7

# 运行容器,需要做数据挂载
# 注意:安装启动mysql,需要配置密码的
# 官方测试:docker run --name some-mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag

# 启动我们的
# -d 后台运行
# -p 端口映射
# -v 卷挂载
# -e 环境配置
# --name 容器名字

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

启动成功之后,我们使用本地的软件navicat来测试连接

image-20210320170918960

# 连接原理:
# navicat - 连接到服务器的3310 --- 3310 和容器内的 3306 映射,这个时候我们就可以连接上了(注意开放3310端口)

image-20210320171116706

测试

  1. 在本地连接Mysql并创建数据库

    image-20210323104917217

  2. 发现服务器目录下同样也多出了这个文件

    image-20210323105001667

  3. 所以就算把mysql容器删除了,但是我们挂载在本地的数据卷并不会丢失!

具名和匿名挂载

匿名挂载

# 匿名挂载,-P随机映射端口
-v 容器内路径!
docker run -d -P --name nginx01 -v /etc/nginx nginx

# 查看所有的卷的情况
docker volume ls

# 这里发现,这种就是匿名挂载,我们在 -v 只写了容器内的路径,没有写容器外的路径

image-20210323105853180

具名挂载

# 具名挂载
docker run -d -P --name nginx02 -v juming:/etc/nginx nginx

# 查看所有的卷的情况
docker volume ls

image-20210323110159402

查看挂载的信息和目录

# 查看这个卷
docker volume inspect juming-nginx

image-20210323110527647

所有的docker容器内的卷,没有指定目录的情况下都是在/var/lib/docker/volumes目录下。

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

image-20210323110709008

查看nginx的配置文件

image-20210323110900556

确定是具名挂载还是匿名挂载,还是指定路径挂载

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

拓展:

# 通过 -v 容器内路径:ro    rw 改变读写权限
ro    readonly    # 只读
rw    readwrite    # 可读写

# 一旦设置了容器的权限,容器对我们挂载出来的内容就有限定了!
docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx:ro nginx

# ro 只要看到ro就说明这个路径只能通过宿主机来操作,容器内部无法操作!

初识 Dockersfile

Dockerfile 就是用来构建 docker 镜像的构建文件!命令脚本!

通过这个脚本可以生成镜像,镜像是一层一层的,脚本是一个一个的命令,每个命令就是一层!

# 创建一个dockerfile文件
cd /home

mkdir docker-test-volume

cd docker-test-volume/
vim dockerfile01

# 编写文件内容,的hi零都是大写的,匿名挂载
FROM centos

VOLUME ["volume01", "volume02"]

CMD echo "-----end-----"
CMD /bin/bash

image-20210323123800056

生成镜像

# -f 指定dockerfile文件
# -t 命名镜像
# . 表示在当前路径下生成

docker build -f dockerfile01 -t xiaojiang/centos:1.0 .

image-20210323124140288

查看镜像

image-20210323124211684

启动自己写的容器

# 启动容器
docker run -it 49a93c8bcf07

# 查看容器文件
ls -l

image-20210323124453637

这个卷和外部一定有一个同步的目录,我们在上方使用了匿名挂载

image-20210323124542728

# 查看卷挂载的路径
docker inspect 6e56e2421de7

image-20210323125156803

这种方式我们未来使用的十分多,因为我们通常回构建自己的镜像!

假设构建镜像的时候没有挂载卷,要手动镜像挂载 -v 卷名 容器内路径

数据卷容器

两个 MySQL 同步数据

image-20210323125814307

测试多个容器共享数据

# 启动容器1
docker run -it --name docker01 xiaojiang/centos:1.0
# 按 ctrl + P + Q 退出界面

# 启动容器2并挂载上容器1
docker run -it --name docker02 --volumes-from docker01 xiaojiang/centos:1.0

# 进入docker01容器,编写共享文件
docker attach d3261b8b1c70
cd volumes01
touch docker01

# 在docker02容器中查看

image-20210323131445769

# 创建容器3,挂载到容器2
docker run -it --name docker03 --volumes-from docker01 xiaojiang/centos:1.0

image-20210323131633410

# 在docker03中编写文件,发现在其他容器中同样可以查看到
touch docker03
# 将容器1删除,查看是否回产生影响
docker rm -f docker01

image-20210323132106770

发现数据依然存在

image-20210323132149674

多个mysql实现数据共享

# 启动一个mysql01
docker run -d -p 3310:3306 -v /home/mysql/conf:/etc/mysql/conf.d -v /home/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql:5.7

# 启动mysql02
docker run -d -p 3311:3306 -e MYSQL_ROOT_PASSWORD=123456 --name mysql02 --volumes-from mysql01 mysql:5.7

# 这个时候就可以实现两个容器数据同步!

结论:

容器之间配置信息的传递,数据卷容器的生命周期一直持续到没有容器使用为止。

一旦持久化到了本地,这个时候本地的数据是不会删除的!

11、DockerFile

DockerFile 介绍

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

构建步骤:

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

查看一下官方用法,访问 https://hub.docker.com/,搜索centos,点击下方版本信息即可跳转到对应 GitHub 仓库查看源码

image-20220527225921014

image-20220527230035128

但是很多官方镜像都是基础包,很多功能没有,通常需要我们自己搭建镜像!

DockerFile 构建过程

基础知识

  1. 每个保留关键字(指令)都是必须大写字母

  2. 执行顺序为从上到下

  3. #表示注释

  4. 每一个指令都会创建提交一个新的镜像层,并提交

    image-20220527231105839

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

步骤

DockerFile:构建文件,定义一切的步骤,源代码

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

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

DockerFile 指令

可以通过以下指令,构建自己的镜像

FROM            # 基础镜像,一切从这里开始构建
MAINTAINER        # 镜像是谁写的,姓名 + 邮箱
RUN                # 惊醒构建的时候需要运行的命令
ADD                # 添加其他内容要这个镜像中
WORKDIKR        # 镜像的工作目录
VOLUME            # 挂载的目录,-v
EXPOSE            # 保留端口配置,-p
CMD                # 指定这个容器启动的时候要运行的命令,只有最后一个生效
ENTRYPOINT        # 指定这个容器启动的时候要运行的命令,可以追加命令
ONBUILD            # 当构建一个被继承 DockerFile 这个时候就会运行 ONBUILD 的指令
COPY            # 类似ADD,将我们的文件拷贝到镜像中
ENV                # 构建的时候设置环境变量,-e

image-20220528103602675

实战测试

基础镜像

Docker Hub 中大部分镜像都是从这个基础镜像过来的 FROM scratch,然后配置需要的软件和配置来进行构建

image-20220528124707258

创建一个自己的centos

1、编写 DockerFile 文件

vim mydockerfile-centos

FROM centos
MAINTAINER luxiaojiang<1256240778@qq.com>

ENV MYPATH /usr/local
WORKDIR $MYPATH

RUN yum -y install vim
RUN yum -y install net-tools

EXPOSE 80

CMD echo $MYPATH
CMD echo "----end----"
CMD /bin/bash

2、通过这个文件构建镜像

# 命令 docker build -f dockerfile -t 镜像名:[tag] [文件路径]
docker build -f mydockerfile-centos -t mycentos:1.0 .

image-20220528132801081

报错了:The command ‘/bin/sh -c yum -y install vim’ returned a non-zero code: 1

原因:docker中的centos版本对应不上,需要设置版本,宿主机上的centos是7

FROM centos:7

修改好版本之后即可

image-20220528134158091

3、运行镜像

docker run -it mycentos:1.0

image-20220529004715495

此时可以发现直接进入到工作目录,这是编写 dockerfile 文件的时候设置的

并且发现 ifconfig 和 vim 指令也可以使用了

image-20220529004942637

查看镜像的变更历史

# docker history [镜像id]
docker history af69beb2f34e

image-20220529005138938

CMD 和 ENTRYPOINT 区别

CMD            # 指定容器启动的时候要运行的命令,只有最后一个生效,最后一个替换此前的命令
ENTRYPOINT    # 指定容器启动的时候要运行的命令,可以不断追加命令指令

CMD测试

# 创建 dockerfile 文件
vim dockerfile-cmd-test
FROM centos
CMD ["ls", "-a"]

# 生成镜像
docekr build -f dockerfile-cmd-test -t cmdtest:1.0 .

# 运行镜像
docker run 96ea83f47d80
.
..
.dockerenv
bin
dev
etc
home
lib
lib64
lost+found
media
mnt
opt
proc
root
run
sbin
srv
sys
tmp
usr
var

# 测试追加命令
docker run 96ea83f47d80 -l 
docker: Error response from daemon: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: exec: "-l": executable file not found in $PATH: unknown.
ERRO[0000] error waiting for container: context canceled 

ENTRYPOINT测试

# 创建 dockerfile 文件
vim dockerfile-entrypoint-test
FROM centos
ENTRYPOINT ["ls", "-a"]

# 生成镜像
docker build -f dockerfile-entrypoint-test -t entrypoint-test:1.0 .

# 执行镜像
docker run de9251f23f04
.
..
.dockerenv
bin
dev
etc
home
lib
lib64
lost+found
media
mnt
opt
proc
root
run
sbin
srv
sys
tmp
usr
var

# 追加命令测试
docker run de9251f23f04 -l
total 56
drwxr-xr-x   1 root root 4096 May 29 14:00 .
drwxr-xr-x   1 root root 4096 May 29 14:00 ..
-rwxr-xr-x   1 root root    0 May 29 14:00 .dockerenv
lrwxrwxrwx   1 root root    7 Nov  3  2020 bin -> usr/bin
drwxr-xr-x   5 root root  340 May 29 14:00 dev
drwxr-xr-x   1 root root 4096 May 29 14:00 etc
drwxr-xr-x   2 root root 4096 Nov  3  2020 home
lrwxrwxrwx   1 root root    7 Nov  3  2020 lib -> usr/lib
lrwxrwxrwx   1 root root    9 Nov  3  2020 lib64 -> usr/lib64
drwx------   2 root root 4096 Sep 15  2021 lost+found
drwxr-xr-x   2 root root 4096 Nov  3  2020 media
drwxr-xr-x   2 root root 4096 Nov  3  2020 mnt
drwxr-xr-x   2 root root 4096 Nov  3  2020 opt
dr-xr-xr-x 114 root root    0 May 29 14:00 proc
dr-xr-x---   2 root root 4096 Sep 15  2021 root
drwxr-xr-x  11 root root 4096 Sep 15  2021 run
lrwxrwxrwx   1 root root    8 Nov  3  2020 sbin -> usr/sbin
drwxr-xr-x   2 root root 4096 Nov  3  2020 srv
dr-xr-xr-x  13 root root    0 May 29 14:00 sys
drwxrwxrwt   7 root root 4096 Sep 15  2021 tmp
drwxr-xr-x  12 root root 4096 Sep 15  2021 usr
drwxr-xr-x  20 root root 4096 Sep 15  2021 var

制作 Tomcat 镜像

1、准备镜像文件 tomcat 压缩包,jdk 的压缩包

下载jdk:https://www.oracle.com/java/technologies/downloads/

image-20220531200714897

下载tomcat:https://tomcat.apache.org/download-90.cgi

image-20220531200649800

上传至服务器

image-20220531203510027

2、编写 dockerfile 文件,官方命名 Dockerfile,构建镜像的时候 build 会自动寻找这个文件,就不需要 -f 指定了

# 创建文件
touch redme.txt

# 编写 dockerfile
# COPY 用于直接复制文件
# ADD 会添加并解压
vim Dockerfile

FROM centos:7
MAINTAINER luxiaojiang<1256240778@qq.com>

COPY readme.txt /usr/local/readme.txt

ADD jdk-8u333-linux-x64.tar.gz /usr/local/
ADD apache-tomcat-9.0.63.tar.gz /usr/local/

RUN yum -y install vim

ENV MYPATH /usr/local
WORKDIR $MYPATH

ENV JAVA_HOME /usr/local/jdk1.8.0_333
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.63
ENV CATALINA_BASH /usr/local/apache-tomcat-9.0.63

ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin

EXPOSE 8080

CMD $CATALINA_HOME/bin/startup.sh && tail -F $CATALINE_HOME/bin/logs/catalina.out

3、构建镜像

# 因为文件直接命令为 Dockerfile,所以不需要加 -f 命令
docker build -t luxiaojiang123/diytomcat:1.0 .

image-20220531205805983

4、运行镜像

# -d 后台运行
# -p 指定端口映射
# --name 设置容器名称
# -v 挂在目录
docker run -d -p 9000:8080 --name lxjtomcat -v /usr/local/docker/tomcat/test:/usr/local/apache-tomcat-9.0.63/webapps/test -v /usr/local/docker/tomcat/logs:/usr/local/apache-tomcat-9.0.63/logs luxiaojiang123/diytomcat

5、进入容器

docker exec -it acea24c093fd /bin/bash

6、退出容器,测试访问

exit 

# 在宿主机访问测试
curl localhost:9000

image-20220531222907177

7、测试目录挂载

# 进入容器
docker exec -it 775e83020e9b /bin/bash
cd /usr/local/apache-tomcat-9.0.63/webapps/test

8、在宿主机创建 jsp 文件

cd /usr/local/docker/tomcat/test
vim index.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>hello,luxiaojiang</title>
    </head>
    <body>
        hello, world! <br/>
        <%
           System.out.println("----my test web logs-----");
         %>
    </body>
</html>

9、可以查看到容器内的挂载目录也新增了一个文件

image-20220601110737543

10、访问测试

image-20220601113502498

项目部署成功之后就可以直接访问了

以后的开发步骤:需要掌握 Dockerfile 的编写!我们之后的一切都是使用 docker 镜像来发布运行!

发布到 DockerHub

DockerHub

1、地址:https://hub.docker.com/

image-20220601113611511

2、注册完账号之后直接在服务器上进行登录

(base) ?  tomcat 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

3、登录完成之后直接提交就行

image-20220601114205873

4、提交镜像

# docker push [用户名]/[镜像名]
docker push luxiaojiang123/diytomcat

image-20220602003144618

5、登录 DockerHub 查看是否上传成功

image-20220602003226575

image-20220602003505172

发布到阿里云

1、登录阿里云

2、找到容器镜像服务

3、创建命名空间

image-20220603145510984

4、创建镜像仓库

image-20220603145555686

选择本地仓库

image-20220603145657292

就可以看到相应的操作指南了

image-20220603150044156

5、测试

# 进行登录
docker login --username=晓江233 registry.cn-shenzhen.aliyuncs.com

image-20220603150306528

# 重新构建镜像,命名为 [用户名]/[镜像名]
docker build -t registry.cn-shenzhen.aliyuncs.com/luxiaojiang/diytomcat:1.0 .

# 也可以直接重命名本地镜像名称,并生成相应副本(不是修改原镜像)
docker tag [镜像id] [仓库名]:[版本]

image-20220603160708922

# 推送镜像到阿里云
docker push registry.cn-shenzhen.aliyuncs.com/luxiaojiang/diytomcat:1.0

image-20220603151515840

上传成功之后就可以在阿里云中查看到对应的镜像了

image-20220603155939355

小结

image-20220603154239954

12、Docker网络

Docker0

测试

1、获取 docker 的 ip 地址

ip addr

image-20220603230617079

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

image-20220604000636559

2、启动 tomcat 容器

docker run -d -P --name tomcat01 tomcat

3、查看容器的 ip 地址

docker exec -it tomcat01 ip addr

报错:OCI runtime exec failed: exec failed: unable to start container process: exec: “ip”: executable file not found in $PATH: unknown

image-20220604001705002

解决:

# 执行以下命令
apt update && apt install -y iproute2

4、发现容器启动的时候会得到一个 eth0 ip地址,这是 docker 分配的,并且可以直接 ping 通 docker 容器内部

image-20220604002118769

原理

1、我们每启动一个 docker 容器,docker 就会给 docker 容器分配一个 ip,我们只要安装了 docker,就会有一个网卡 docker0

2、使用桥接模式,evth-pair 技术

3、再启动一个容器测试,发现又多一个一对网卡

image-20220604002613317

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

4、测试两个容器能否相互连接

# 查看 tomcat01 的 ip 地址
docker exec -it tomcat01 ip addr

# 使用 tomcat02 ping tongcat01
docker exec -it tomcat02 ping 172.17.0.2

报错:OCI runtime exec failed: exec failed: unable to start container process: exec: “ping”: executable file not found in $PATH: unknown

image-20220604004120694

解决:算了,并没有解决,反正能 ping 通的

docker exec -it tomcat02 /bin/bash
apt-get update && apt-get install iputils-ping

5、原理图如下

image-20220604004856682

结论:tomcat01 和 tomcat02 是公用一个路由器的,docker0

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

小结

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

image-20220604005054660

Docker 中的所有的网络接口都是虚拟的,虚拟的转发效率高

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

查看网络

# 查看网络列表
docker network ls

image-20220604110409054

# 查看桥接网络
docker inspect 07cb58b73881

这是 docker0 的网络配置

image-20220604110713257

往下可以查看到 docker 的容器网络

image-20220604110503756

思考

编写了一个微服务,database url = ip;项目一重启,数据库 ip 就换掉了,我们希望可以解决这个问题,可以通过名字来进行访问容器

# 如果直接使用容器名ping不通
docker exec -it tomcat02 ping tomcat01

使用 –link 命令

# 重新启动一个容器
docker run -d -P --name tomcat03 --link tomcat02 tomcat

这样启动之后,tomcat03 就可以 ping 通tomcat02

注意:当时 tomcat02 不能 ping 通 tomcat03

原理

# 查看 tomcat03 的网络本地配置
docker exec -it cat /etc/hosts

image-20220604111521973

# 查看 tomcat02 的网络配置
docker exec -it tomcat02 cat /etc/hosts

这里并没有 tomcat03 的网络映射,所以 tomcat02 连接不通 tomcat03

image-20220604111655312

本质:–link 就是在 hosts 配置中增加一个映射关系

但是现在已经不建议使用 –link 了

自定义网络

查看所有的 docker 网络

image-20220604112013286

网络模式

bridge:桥接 docker(默认)

none:不配置网络

host:和宿主机共享网络

container:容器网络连通(用的少,局限很大)

测试

# 我们直接启动的命令自动使用 --net bridge,而这个就是我们的docker0
docker run -d -P --name tomcat01 tomcat
docker run -d -P --name tomcat01 --net bridge tomcat

# docker0 特点:默认,不能通过容器名访问,--link 可以打通连接

自定义网络

# 创建网络
# --driver 定义网络模式
# --subnet 设置掩码,/16 表示前面八位二进制固定,剩下 255 * 255 - 2 个地址
# --gateway 设置网关
docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet

image-20220604113210142

image-20220604113429400

启动容器并配置网络

# --net 用于设置网络
docker run -d -P --name tomcat-net-01 --net mynet tomcat
docker run -d -P --name tomcat-net-02 --net mynet tomcat

# 查看自定义网络
docker network inspect mynet

此时可以看到自定义网络中新增了两个容器的网络信息

image-20220604113731006

测试连接

# 以下请求都能 ping 通
docker exec -it tomcat-net-01 ping 192.168.0.3
docker exec -it tomcat-net-01 ping tomcat-net-02

我们自定义的网络 docker 都已经帮我们维护好了对应的关系

好处

可以用于配置不通的网络集群,例如 redis、mysql 各自的网络集群

网络连通

image-20220604124515522

image-20220604124609840

# 测试打通
docker network connect mynet tomcat01

成功将 tomcat01 添加在 mynet 网络中,此时一个容器有两个 ip,配置之后,tomcat01 就能和 tomcat-net-01 连通了

image-20220604124749049

实战:部署 Redis 集群

image-20220604125635082

1、创建网络

docker network create redis --subnet 172.38.0.0/16

2、编写脚本创建六个 redis 配置

for port in $(seq 1 6); \
do \
mkdir -p /usr/local/docker/redis/node-${ port} /conf
touch /usr/local/docker/redis/node-${ port} /conf/redis.conf
cat << EOF >/usr/local/docker/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

直接粘贴到xshell中执行即可

image-20220604203411018

3、启动六个 redis 容器

for port in $(seq 1 6); \
do \
docker run -p 637${ port} :6379 -p 1637${ port} :16379 --name redis-${ port}  -v /usr/local/docker/redis/node-${ port} /data:/data -v /usr/local/docker/redis/node-${ port} /conf/redis.conf:/etc/redis/redis.conf -d --net redis --ip 172.38.0.1${ port}  redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf 
done

image-20220604211937224

4、创建集群

# 进入一个 redis 容器中
docker exec -it redis-1 /bin/sh

# 创建集群
# --replicas 1 中的1其实代表的是一个比例,就是主节点数/从节点数的比例,先是3个主节点,然后是3个从节点
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

image-20220604212636066

5、连接 redis 集群

# -c 代表连接集群
redis-cli -c

# 查看集群信息
cluster info

# 查看节点
cluster nodes

image-20220604212904002

6、测试存值,并且关闭一台服务

set name xiaojiang

image-20220604213200537

可以发现,进行存值的时候,是主机轮流进行处理

7、停止 redis-2 容器进行测试

# 新建命令窗口,停止 redis-2
docker stop redis-2

image-20220604213442546

8、再次取值

get name

image-20220604213513944

此时发现是从 redis-6 从机中取到值,查看集群节点,可以看到 redis-2 发生故障,redis-6 成为主机,重启 redis-2 容器之后,发现 redis-2 成为从机

image-20220604213730948

SpringBoot微服务打包成Docker镜像

1、构建 springboot 项目,编写一个 hello,world 的 controller 就行了

2、打包应用

3、编写 dockerfile

FORM java:8
COPY *.jar /app.jar
CMD ["--server.port=8080"]
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "/app.jar"]

4、将 jar 和 dockerfile 文件上传到服务器

image-20220605002518856

5、构建镜像

docker build -t springboot-test .

6、运行镜像

docker run -d -p 9000:8080 springboot-test

image-20220605002747710

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

但是如果有很多个镜像需要启动,则会很麻烦,所以后续就需要使用 Docker Compose 容器编排等内容。

13、Docker 小结

拉取镜像

1、登录 DockerHub 官网进行搜索镜像:https://hub.docker.com/

image-20220605214030601

2、复制项目里面的拉取代码运行就可以了

image-20220605214116103

运行镜像

# -it 交互方式运行 -d 后台运行
# --name 定义容器名
# -p 端口映射 -P 随机端口
# -v 目录挂载
docker run -it --name [容器名] -p 9000:8080 -v /usr/local/docker:/docker [镜像名]

提交容器

# 提交容器成为一个新的副本
# 命令和 git 原理类似
docker commit -m="提交的描述信息" -a="作者" [容器id] [目标镜像名]:[TAG]

提交镜像

1、提交到 DockerHub

# 登录 DockerHub
docker login -u luxiaojiang123

# 生成镜像副本,将目标镜像命名为 [用户名]/[镜像名]
docker tag [原镜像]:[TAG] [目标镜像]:[TAG]

# docker push [用户名]/[镜像名]
docker push luxiaojiang123/diytomcat

2、提交到 阿里云容器镜像服务

# 登录账号
docker login --username=晓江233 registry.cn-shenzhen.aliyuncs.com

# 生成镜像副本
docker tag [ImageId] registry.cn-shenzhen.aliyuncs.com/luxiaojiang/diytomcat:[镜像版本号]

# 提交镜像
docker push registry.cn-shenzhen.aliyuncs.com/luxiaojiang/diytomcat:[镜像版本号]