一、Docker入门

1. Docker 为什么会出现

2. DevOps(开发、运维)

3. 名词解释

  • 镜像(image)
    • Docker 镜像就好比是一个模板,可以通过这个模板来创建容器服务,tomcat 镜像 ===> run ===> tomcat01 容器, 通过这个镜像可以创建多个容器(最终服务运行或者项目运行就是在容器中的)
  • 容器(container)
    • Docker 利用容器技术,独立运行一个或者一组应用, 通过镜像来创建的
    • 启动,停止,删除,基本命令!
    • 就目前可以把这个容器理解为一个建议的 linux 系统
  • 仓库(repository)
    • 存放镜像的地方
    • Docker Hub(默认是国外的)
    • 阿里云,都有容器服务(配置镜像加速!)

4. 安装 docker

4.1 安装前环境查看

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 系统内核
>> uname -r
5.15.0-1023-azure

# 系统版本
>> cat /etc/or-release
NAME="Ubuntu"
VERSION="20.04.5 LTS (Focal Fossa)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 20.04.5 LTS"
VERSION_ID="20.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=focal
UBUNTU_CODENAME=focal

4.2 卸载旧版本

sudo apt-get remove docker docker-engine docker.io containerd runc

4.3 使用 Docker 仓库进行安装

1. 设置仓库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 更新apt包索引
$ sudo apt-get update

# 安装apt依赖包,用于通过HTTPS来获取仓库
$ sudo apt-get install \
apt-transport-https \
ca-certificates \
curl \
gnupg-agent \
software-properties-common

# 添加Docker的官方秘钥 [验证如下]
$ curl -fsSL https://mirrors.ustc.edu.cn/docker-ce/linux/ubuntu/gpg | sudo apt-key add -

# 设置稳定版仓库
$ sudo add-apt-repository \
"deb [arch=amd64] https://mirrors.ustc.edu.cn/docker-ce/linux/ubuntu/ \
$(lsb_release -cs) \
stable"
  • 秘钥添加验证

    1
    2
    3
    4
    5
    6
    7
    # 9DC8 5822 9FC7 DD38 854A E2D8 8D81 803C 0EBF CD88 通过搜索指纹的后8个字符,验证您现在是否拥有带有指纹的密钥。
    $ sudo apt-key fingerprint 0EBFCD88

    pub rsa4096 2017-02-22 [SCEA]
    9DC8 5822 9FC7 DD38 854A E2D8 8D81 803C 0EBF CD88
    uid [ unknown] Docker Release (CE deb) <docker@docker.com>
    sub rsa4096 2017-02-22 [S]

2. 安装 Docker Engine-Community

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#更新 apt 包索引
$ sudo apt-get update

# 安装最新版本的 Docker Engine-Community 和 containerd ,或者转到下一步安装特定版本:
$ sudo apt-get install docker-ce docker-ce-cli containerd.io

# 要安装特定版本的 Docker Engine-Community,请在仓库中列出可用版本,然后选择一种安装。列出您的仓库中可用的版本:
$ apt-cache madison docker-ce
docker-ce | 5:18.09.1~3-0~ubuntu-xenial | https://mirrors.ustc.edu.cn/docker-ce/linux/ubuntu xenial/stable amd64 Packages
docker-ce | 5:18.09.0~3-0~ubuntu-xenial | https://mirrors.ustc.edu.cn/docker-ce/linux/ubuntu xenial/stable amd64 Packages
docker-ce | 18.06.1~ce~3-0~ubuntu | https://mirrors.ustc.edu.cn/docker-ce/linux/ubuntu xenial/stable amd64 Packages
docker-ce | 18.06.0~ce~3-0~ubuntu | https://mirrors.ustc.edu.cn/docker-ce/linux/ubuntu xenial/stable amd64 Packages
...
# 使用第二列中的版本字符串安装特定版本,例如 5:18.09.1~3-0~ubuntu-xenial
$ sudo apt-get install docker-ce=<VERSION_STRING> docker-ce-cli=<VERSION_STRING> containerd.io

# 测试 Docker 是否安装成功(docker --version(-v))
$ sudo docker run hello-world

Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
1b930d010525: Pull complete Digest: sha256:c3b4ada4687bbaa170745b3e4dd8ac3f194ca95b2d0518b417fb47e5879d9b5f
Status: Downloaded newer image for hello-world:latest


Hello from Docker!
This message shows that your installation appears to be working correctly.


To generate this message, Docker took the following steps:
1. The Docker client contacted the Docker daemon.
2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
(amd64)
3. The Docker daemon created a new container from that image which runs the
executable that produces the output you are currently reading.
4. The Docker daemon streamed that output to the Docker client, which sent it
to your terminal.


To try something more ambitious, you can run an Ubuntu container with:
$ docker run -it ubuntu bash


Share images, automate workflows, and more with a free Docker ID:
https://hub.docker.com/


For more examples and ideas, visit:
https://docs.docker.com/get-started/

3. 卸载 docker

1
2
3
4
5
# 删除安装包:
sudo apt-get purge docker-ce

# 删除镜像、容器、配置文件等内容:
sudo rm -rf /var/lib/docker

4.4 查看 docker 版本

1
2
# 需要给予sudo权限
$ sudo docker version

image-20230228234955042

4.5 阿里云镜像加速

  • 为何配置?

    • 国内从 DockerHub 拉取镜像有时会遇到困难,此时可以配置镜像加速器。
    • Docker 官方和国内很多云服务商都提供了国内加速器服务,建议根据运行 docker 的云平台选择对应的镜像加速服务。
  • 配置步骤

    1. 登录阿里云服务器,找到容器镜像服务

    2. 找到镜像加速器

    3. 配置使用

      • ```shell
        sudo mkdir -p /etc/docker
        sudo tee /etc/docker/daemon.json <<-‘EOF’
        {
        “registry-mirrors”: [“https://6nl6ynme.mirror.aliyuncs.com“]
        }
        EOF
        sudo systemctl daemon-reload
        sudo systemctl restart docker
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30

        - 另外可配置多个,如`AZURE` -> `dockerhub.azk8s.cn` (/etc/docker/daemon.json)

        ## 5\. 底层原理

        - 底层原理

        - Docker Engine 是一个客户端-服务器应用程序,具有以下主要组件:

        - 一个服务器,它是一种长期运行的程序,称为守护进程(dockerd 命令)
        - 一个 REST API,它指定程序可以用来与守护进程对话并指示它做什么的接口。

        - Docker 是一个**Client Server 结构的系统**,Docker 守护进程运行在主机上,然后通过 Socket 连接从客户 端访问,守护进程从客户端接受命令并管理运行在主机上的容器。**容器,是一个运行时环境就是我们所说的集装箱。**

        <img src="https://s2.loli.net/2023/02/27/JStoUsImMv85ALO.png" style="zoom:80%;" />

        - 为什么 Docker 比 Vm 快

        - docker 有着比虚拟机更少的抽象层。*由于 docker 不需要 Hypervisor 实现硬件资源虚拟化,*运行在 docker 容器上的程序直接使用的都是实际物理机的硬件资源。
        - **docker 利用的是宿主机的内核,而不需要 Guest OS**。因此,当新建一个 容器时,docker 不需要和虚拟机一样重新加载一个操作系统内核。避免引寻、加载操作系统内核返个比较费时费资源的过程,当新建一个虚拟机时,虚拟机软件需要加载 Guest OS,返个新建过程是分钟级别的。**而 docker 由于直接利用宿主机的操作系统,则省略了返个过程,因此新建一个 docker 容器只需要几秒钟。**

        ![](https://img-blog.csdnimg.cn/20200411132454634.png)

        ## 6. 避免权限问题

        ```shell
        sudo groupadd docker #添加docker用户组
        sudo gpasswd -a $USER docker #将登陆用户加入到docker用户组中
        newgrp docker #更新用户组
        docker ps #测试docker命令是否可以使用sudo正常使用

二、Docker 基本命令

1. Docker 的常用命令

在这里插入图片描述

2. 帮助命令

1
2
3
4
5
6
7
# docker版本信息
docker version

# 系统级别的信息,包括镜像和容器的数量
docker info

docker 命令 --help

2. 镜像命令

images - 查看所有本地主机上的镜像

1
2
3
4
5
6
7
8
9
10
11
12
13
14
bayyy@bayzju:/$ sudo docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest feb5d9fea6a5 17 months ago 13.3kB

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

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

search - 查找镜像

image-20230301005232057

1
2
# 可选项
--filter=STARS=3000 # 搜素出来的镜像就是STARS大于3000的

pull - 下拉镜像

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# 下载镜像 docker pull 镜像名[:tag]

[root@iZ2zeg4ytp0whqtmxbsqiiZ ~]# docker pull mysql
Using default tag: latest # 如果不写tag,默认就是latest
latest: Pulling from library/mysql
bf5952930446: Pull complete # 分层下载,docker images的核心,联合文件系统
8254623a9871: Pull complete
938e3e06dac4: Pull complete
ea28ebf28884: Pull complete
f3cef38785c2: Pull complete
894f9792565a: Pull complete
1d8a57523420: Pull complete
6c676912929f: Pull complete
ff39fdb566b4: Pull complete
fff872988aba: Pull complete
4d34e365ae68: Pull complete
7886ee20621e: Pull complete
Digest: sha256:c358e72e100ab493a0304bda35e6f239db2ec8c9bb836d8a427ac34307d074ed # 签名
Status: Downloaded newer image for mysql:latest
docker.io/library/mysql:latest # 真实地址


# 等价于
docker pull mysql
# ===
docker pull docker.io/library/mysql:latest


# 指定版本下载
[root@iZ2zeg4ytp0whqtmxbsqiiZ ~] docker pull mysql:5.7
5.7: Pulling from library/mysql
bf5952930446: Already exists
8254623a9871: Already exists
938e3e06dac4: Already exists
ea28ebf28884: Already exists
f3cef38785c2: Already exists
894f9792565a: Already exists
1d8a57523420: Already exists
5f09bf1d31c1: Pull complete
1b6ff254abe7: Pull complete
74310a0bf42d: Pull complete
d398726627fd: Pull complete
Digest: sha256:da58f943b94721d46e87d5de208dc07302a8b13e638cd1d24285d222376d6d84
Status: Downloaded newer image for mysql:5.7
docker.io/library/mysql:5.7

# 查看本地镜像
bayyy@bayzju:/$ sudo docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mysql latest 3218b38490ce 14 months ago 516MB
hello-world latest feb5d9fea6a5 17 months ago 13.3kB

rmi - 删除镜像

1
2
3
$ docker rmi -f IMAGE ID	# 删除指定镜像
$ docker rmi -f IMAGE ID1 IMAGE ID2 IMAGE ID3 # 删除多个镜像
$ sudo docker rmi -f $(sudo docker images -aq) # 删除所有镜像

3. 容器命令

说明: 我们有了镜像才可创建容器,linux,下载一个 centos 镜像来测试学习

1
$ docker pull centos

新建容器并启动 run

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
$ docker run [options] image

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

# 测试,启动并进入容器
bayyy@bayzju ~/Desktop> sudo docker run -it centos
[root@c78f426ac40a /]#
[root@c78f426ac40a /]# ls # 查看容器内的centos, 很多命令是不完善的
bin dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var
# 从容器中退回主机
[root@c78f426ac40a /]# exit
exit
bayyy@bayzju ~/Desktop> ls
CS50X/ Duke_C/ Missing_Semester/
bayyy@bayzju ~/Desktop>

image-20230303225252316

列出所有的运行的容器 ps

1
2
3
4
$ docker ps        # 列出当前正在运行的容器
-a # 列出正在运行的容器包括历史容器
-n=? # 显示最近创建的容器
-q # 只显示当前容器的编号

image-20230303225654295

退出容器 exit

1
2
3
4
5
exit            # 直接退出容器并关闭
Ctrl + P + Q # 容器不关闭退出
# 恢复后台运行的容器
docker exec -it containerID bash
docker attach containerID

删除容器 rm

1
2
3
4
docker rm  容器id	# 删除指定容器,不能删除正在运行的容器
docker rm -f 容器id # 强制删除指定容器
docker rm -f $(docker ps -aq) # 删除所有容器
docker ps -a -q|xargs docker rm -f # 删除所有的容器

启动和停止容器的操作

1
2
3
4
docker start 容器id           # 启动容器
docker restart 容器id # 重启容器
docker stop 容器id # 停止当前正在运行的容器
docker kill 容器id # 强制停止当前的容器

4. 常用的其他命令

后台启动容器 docker run -d

1
2
3
4
5
6
# 命令 docker run -d 镜像名
[root@iZ2zeg4ytp0whqtmxbsqiiZ /]# docker run -d centos
# 问题
docker ps, 发现centos停止了
# 常见的坑, docker 容器使用后台运行, 就必须要有一个前台进程,docker发现没有应用,就会自动停止
# nginx, 容器启动后,发现自己没有提供服务,就会立即停止,就是没有程序了

查看日志 docker log

1
2
3
4
5
6
docker logs -tf --tail number 容器id
# 显示日志
-tf # -t 显示时间戳 -f 跟随最新日志打印
<!-- --tail number # 显示日志条数 -->
-n number # 显示日志条数
$ docker logs -tf --tail 10 a0d580a21251

image-20230304001535631

查看容器中进程信息 ps

1
2
# 命令 docker top 容器id
$ docker top df358bc06b17

image-20230304001801071

查看镜像的元数据 inspect

1
2
# 命令docker inspect 容器id
$ sudo docker inspect a57ef429f2910d677fc13a2295b98c85b624aaac1d2ca1c00a651a3f0ad71fae

image-20230304002345333

进入当前正在运行的容器 exec / attach

1
2
3
4
5
6
7
# 我们通常容器使用后台方式运行的, 需要进入容器,修改一些配置
# 命令
docker exec -it 容器id /bin/bash
# 方式二
docker attach 容器id
# docker exec # 进入容器后开启一个新的终端,可以在里面操作
# docker attach # 进入容器正在执行的终端,不会启动新的进程

从容器中拷贝文件到主机 cp

1
2
3
4
$ docker cp 容器id:容器内路径    目的地主机路径
bayyy@bayzju ~/Desktop> sudo docker cp 6d512830d6bf:/home/test ~/Desktop/
Preparing to copy...
Successfully copied 1.536kB to /home/bayyy/Desktop/

image-20230304211830711

小结图

image-20230304212327022

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
attach	Attach to a running container	# 当前she11下attach连接指定运行镜像
build Build an image from a Dockerfile # 通过Dockerfile定制镜像
commit Create a new image from a container changes # 提交当前容器为新的镜像
cp copy files/folders from the containers filesystem to the host path # 从容器中拷贝指定文件或者目录到宿主机中
create Create a new container # 创建一个新的容器,同run,但不启动容器
diff Inspect changes on a container's filesystem # 查看 docker 容器变化
events Get real time events from the server # 从docker服务获取容器实时事件
exec Run a command in an existing container # 在已存在的容器上运行命令
export stream the contents of a container as a tar archive # 导出容器的内容流作为一个 tar 归档文件[对应import ]
history Show the history of an image # 展示一个镜像形成历史
images List images # 列出系统当前镜像
import Create a new filesytem imnage from the contents of a tarball # 从tar包中的内容创建一个新的文件系统映像[对应export]
info Display system-wide information # 显示系统相关信息
inspect Return low-level information on a container # 查看容器详细信息
kill kill a running container # ki11指定docker容器
load Load an image from a tar archive # 从一个tar包中加载一个镜像[对应save]
login Register or Login to the docker registry server # 注册或者登陆一个 docker 源服务器
logout Log out from a Docker registry server # 从当前Docker registry退出
lopgs Fetch the logs of a container # 输出当前容器日志信息
port Lookup the public-facing port which is NAT-ed to PRIVATE_PORT # 查看映射端口对应的容器内部源
pause Pause all processes within a container # 暂停容器
ps List containers # 列出容器列表
pull Pull an image or a repository from the docker registry server # 从docker镜像源服务器拉取指定键像或者库镜像
push Push an image or a repository to the docker registry server # 推送指定镜像或者库镜像至 docker 服务器
restart Restart a running container # 重启运行的容器
rm Remove one or more containers # 移除一个或者多个容器
rmi Remove one or more images # 移除一个或多个镜像[无容器使用该镜像才可删除,否则需删除相关容器才可继续或-f 强制删除)
run Run a command in a new container # 创建一个新的容器并运行一个命令
save Save an image to a tar archive # 保存一个镜像为一个tar包[对应1oad]
search Search for an image on the Docker Hub # 在docker hub中搜索镜像
start Start a stopped containers # 启动容器
stop Stop a running containers # 停止容器
tag Tag an image into a repository # 给源中镜像打标签
top Lookup the running processes of a container # 查看容器中运行的进程信息
unpause Unpause a paused container # 取消暂停容器
version Show the docker version information # 查看docker版本号
wait Block until a container stops, then print its exit code # 截取容器停止时的退出状态值

三、Docker 部署软件实战

1.Docker 部署软件实战

Docker 安装 Nginx

1
2
3
4
5
6
7
8
# 1. 搜索镜像 search 建议去docker hub搜索,可以看到帮助文档
# 2. 下载镜像 pull
# 3. 运行测试

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

image-20230304214447739

端口暴露概念

在这里插入图片描述

2. Docker 安装 Tomcat

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 官方的使用
docker run -it --rm tomcat:9.0
# 我们之前的启动都是后台的,停止了容器之后, 容器还是可以查到
# docker run -it --rm 一般用来测试,用完就删

# 下载再启动
docker pull tomcat

# 启动运行
docker run -d -p 3344:8080 --name tomcat01 tomcat
# 测试访问没有问题

# 进入容器
docker exec -it tomcat01 /bin/bash
# 发现问题:
# 1.linux命令少了
# 2. webapps下内容为空,阿里云净吸纳过默认是最小的镜像,所有不必要的都剔除了,保证最小可运行环境即可

3. Docker 部署 es + kibana

1
2
3
4
5
6
7
8
9
10
11
# es 暴露的端口很多
# es 十分的耗内存
# es 的数据一般需要放置到安全目录! 挂载
# --net somenetwork 网络配置
# 启动elasticsearch
docker run -d --name elasticsearch --net somenetwork -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" elasticsearch:7.6.2

# 启动了linux就卡主了
$ docker stats 查看cpu状态
# 增加内存限制,修改配置文件 -e 环境配置修改
docker run -d --name elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -e ES_JAVA_OPTS="-Xms64m -Xmx512m" elasticsearch:7.6.2

image-20230304235114048

4. 可视化

portainer(先用这个)

1
2
3
4
5
6
7
8
docker run -d -p 8088:9000 --restart=always -v /var/run/docker.sock:/var/run/docker.sock --privileged=true portainer/portainer

# 测试
$ curl localhost:8088
<!DOCTYPE html><html lang="en" ng-app="portainer">

# 外网访问
http://ip:8088

image-20230305205244059

image-20230305205307675

image-20230305205431965

Rancher(CI/CD 再用)

三、Docker 原理

1. Docker 镜像加载原理

UnionFS(联合文件系统)

UnionFS(联合文件系统):Union 文件系统(UnionFS)是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下(unite several directories into a single virtual filesystem)。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 等等。

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

2. 分层原理

  • 下载时候的日志输出是一层一层的在下载。

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

  • 查看镜像分层的方式可以通过 docker image inspect 命令 —> layers

  • 所有的 Docker 镜像都起始于一个基础镜像层,当进行修改或增加新的内容时,就会在当前镜像层之上,创建新的镜像层。举一个简单的例子,假如基于 Ubuntu Linux16.04 创建一个新的镜像,这就是新镜像的第一层;如果在该镜像中添加 Python 包,就会在基础镜像层之上创建第二个镜像层;如果继续添加一个安全补丁,就会创建第三个镜像层。该镜像当前已经包含 3 个镜像层,如下图所示(这只是一个用于演示的很简单的例子)。

    image-20230305210732259

Docker 镜像都是只读的,当容器启动时,一个新的可写层被加载到镜像的顶部!
这一层就是我们通常说的容器层,容器之下的都叫镜像层!

3. commit 镜像

1
2
3
4
docker commit 提交容器成为一个新的版本
# 命令和git 原理类似
docker commit -m="提交的描述信息" -a="作者" 容器id 目标镜像名:[TAG]
docker commit -a="xiaofan" -m="add webapps app" d798a5946c1f tomcat007:1.0

实战测试

1
2
3
4
5
6
7
8
# 1. 启动一个默认的tomcat
# 2. 发现这个默认的tomcat是没有webapps应用, 镜像的原因,官方镜像默认webapps下面是没有内容的
# 3. 我自己拷贝进去了基本的文件
# 4. 将我们操作过的容器通过commit提价为一个镜镜像!我们以后就使用我们自己制作的镜像了

$ sudo docker run -it -p 8080:8080 --name tomcat01 tomcat bash
$ cp -r webapps.dist/* webapps
$ catalina.sh run # 运行tomcat

image-20230305212722586

五、容器数据卷

1. 容器数据卷

1.1. docker 的理解回顾

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

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

MySQL,容器删了,删库跑路!需求:MySQL数据可以存储在本地!

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

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

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

1.2. 使用数据卷

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

方式二:使用 Dockerfile

1
2
docker run -it -v 主机目录:容器目录
$ docker run -it -v /home/ceshi:/home centos /bin/bash

image-20230305215919461

1.3. 实战:安装 MySQL

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 获取镜像
$ 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 3344:3306 -v ~/Desktop/mysql/conf:/etc/mysql/conf.d -v ~/Desktop/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql1 mysql:5.7
9552bf4eb2b69a2ccd344b5ba5965da4d97b19f2e1a78626ac1f2f8d276fc2ba
# 启动成功之后,我们在本地使用navicat链接测试一下
# navicat链接到服务器的3344 --- 3344 和 容器的3306映射,这个时候我们就可以连接上mysql喽!
# 在本地测试创建一个数据库,查看下我们的路径是否ok!

在这里插入图片描述

1.4. 匿名和具名挂载

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 匿名挂载
docker run -d -P --name nginx01 -v /etc/nginx nginx
-v 容器内路径
-P 随机指定端口
# 这里发现,这种情况就是匿名挂载,我们在-v 后面只写了容器内的路径,没有写容器外的路径!

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

# 具名挂载
$ docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx nginx
# 通过-v 卷名:容器内的路径

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

image-20230305222830185

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

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

1
2
3
4
# 如何确定是具名挂载还是匿名挂载,还是指定路径挂载!
-v 容器内路径 # 匿名挂载
-v 卷名:容器内路径 # 具名挂载
-v /主机路径:容器内路径 # 指定路径挂载

拓展

1
2
3
4
5
6
# 通过 -v 容器内容路径 ro rw 改变读写权限
ro readonly # 只读
rw readwrite # 可读可写
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 只要看到ro就说明这个路径只能通过宿主机来操作,容器内容无法操作

六、DockerFile

初始 DockerFile

DockerFile 就是用来狗之间 docker 镜像的构建文件!命令脚本!先体验一下!

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

1
2
3
4
5
6
7
8
9
10
# 创建一个dockerfile文件, 名字可以随机
# 文件的内容 指定(大写) 参数
FROM centos

VOLUME ["volume01", "volume02"]

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

# 这里的每一个命令都是镜像的一层!

image-20230305224949906

1
# 启动自己的容器

在这里插入图片描述

这个卷和外部一定有一个同步的目录!

在这里插入图片描述

image-20230305225935827

测试一下刚才的文件是否同步到主机上了!

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

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

数据卷容器

多个 mysql 同步数据!

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

多个 mysql 实现数据共享

1
2
$ docker run -d -p 3344:3306 -v /etc/mysql/conf.d -v /var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql:5.7
$ docker run -d -p 3344:3306 -v /etc/mysql/conf.d -v /var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql02 --volumes-from mysql01 mysql:5.7

结论

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

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

DockerFile

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

构建步骤

  1. 编写一个 dockerFile 文件

  2. docker build 构建成为一个镜

  3. docker run 运行镜像

  4. docker push 发布镜像(DockerHub、阿里云镜像)

  • 官方:

image-20230305231424144

很多官方镜像都像是基础包,很多功能都不具备,我们通常会自己搭建自己的镜像!

官方既然可以制作镜像,能我们一样可以!

DockerFile 构建过程

基础知识:

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

在这里插入图片描述

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

Docker 镜像逐渐成为企业的交互标准,必须要掌握!

步骤:开发,部署, 运维….. 缺一不可!

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

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

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

DockerFile 指令说明

在这里插入图片描述

1
2
3
4
5
6
7
8
9
10
11
12
FROM            # 基础镜像,一切从这里开始构建
MAINTAINER # 镜像是谁写的, 姓名+邮箱
RUN # 镜像构建的时候需要运行的命令
ADD # 步骤, tomcat镜像, 这个tomcat压缩包!添加内容
WORKDIR # 镜像的工作目录
VOLUME # 挂载的目录
EXPOSE # 保留端口配置
CMD # 指定这个容器启动的时候要运行的命令,只有最后一个会生效可被替代
ENTRYPOINT # 指定这个容器启动的时候要运行的命令, 可以追加命令
ONBUILD # 当构建一个继承本镜像的子镜像时会执行内部命令。
COPY # 类似ADD, 将我们文件拷贝到镜像中
ENV # 构建的时候设置环境变量!

创建一个自己的 centos

  • 给 centos 增加vimifconfig等功能
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 1. 编写Dockerfile的文件
FROM centos:7
MAINTAINER bayyy<475417309@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-20230305234050912

image-20230305234305968

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

image-20230305234443627

CMD 和 ENTRYPOINT 区别

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

七、Dockerfile 制作 tomcat 镜像

准备 Dockerfile

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

在这里插入图片描述

2. 编写 Dockerfile 文件,官方命名Dockerfile, build 会自动寻找这个文件,就不需要-f 指定了!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[root@iZ2zeg4ytp0whqtmxbsqiiZ tomcat]# cat Dockerfile
FROM centos
MAINTAINER xiaofan<594042358@qq.com>

COPY readme.txt /usr/local/readme.txt
ADD jdk-8u73-linux-x64.tar.gz /usr/local/
ADD apache-tomcat-9.0.37.tar.gz /usr/local/

RUN yum -y install vim

ENV MYPATH /usr/local
WORKDIR $MYPATH

ENV JAVA_HOME /usr/local/jdk1.8.0_73
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.37
ENV CATALINA_BASH /usr/local/apache-tomcat-9.0.37
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin

EXPOSE 8080

CMD /usr/local/apache-tomcat-9.0.37/bin/startup.sh && tail -F /usr/local/apache-tomcat-9.0.37/bin/logs/catalina.out

生成启动镜像

1. 构建镜像

docker build -t diytomcat .

2. 启动镜像

docker run -d -p 3344:8080 --name xiaofantomcat1 -v /home/xiaofan/build/tomcat/test:/usr/local/apache-tomcat-9.0.37/webapps/test -v /home/xiaofan/build/tomcat/tomcatlogs/:/usr/local/apache-tomcat-9.0.37/logs diytomcat

3. 访问测试

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

在本地编写 web.xml 和 index.jsp 进行测试

在这里插入图片描述

<?xml version="1.0" encoding="UTF-8"?><web-app version="2.4"     xmlns="http://java.sun.com/xml/ns/j2ee"     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee         http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">        </web-app>

<%@ page language="java" contentType="text/html; charset=UTF-8"    pageEncoding="UTF-8"%><!DOCTYPE html><html><head><meta charset="utf-8"><title>hello. xiaofan</title></head><body>Hello World!<br/><%System.out.println("-----my test web logs------");%></body></html>

发现:项目部署成功, 可以直接访问 ok!

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

在这里插入图片描述

发布自己的镜像到 Docker Hub

Docker Hub

  1. 确定这个账号可以登录

image-20230306225656561

  1. 在我们的服务器上提交自己的镜像

    1
    2
    3
    4
    5
    6
    7
    8
    9
    push到我们的服务器上
    $ docker push diytomcat
    The push refers to repository [docker.io/library/diytomcat]2eaca873a720: Preparing 1b38cc4085a8: Preparing 088ebb58d264: Preparing c06785a2723d: Preparing 291f6e44771a: Preparing denied: requested access to the resource is denied
    # 拒绝
    # push镜像的问题?
    The push refers to repository [docker.io/1314520007/diytomcat]An image does not exist locally with the tag: 1314520007/diytomcat

    # 解决,增加一个tag
    $ docker tag diytomcat 1314520007/tomcat:1.0

image-20230306230317962

image-20230306230351157

发布到阿里云镜像服务上

  1. 登录阿里云
  2. 找到容器镜像服务
  3. 创建命名空间

在这里插入图片描述

  1. 创建容器镜像

在这里插入图片描述

  1. 点击仓库名称,参考官方文档即可

在这里插入图片描述

总结

在这里插入图片描述

在这里插入图片描述

八、Docker 容器互联

1. Docker 网络

链接 Docker0

测试网络 ip addr

在这里插入图片描述

三个网络

1
2
3
4
5
6
7
8
9
10
# 问题: docker是如何处理容器网络访问的?
$ docker run -d -P --name tomcat01 tomcat:7.0

# 查看容器内部的网络地址
$ docker exec -it tomcat01 ip addr
# 发现容器启动的时候得到一个eth0@if115 ip地址,docker分配的!

# 思考: linux 能不能ping通容器?

# linux 可以 ping 通docker容器内部!

image-20230306234328231

原理

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

再次测试 ip addr

image-20230306234822764

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

image-20230306234800255

1
2
3
4
# 我们发现这个容器带来网卡,都是一对对的
# veth-pair 就是一对的虚拟设备接口,他们都是成对出现的,一端连着协议,一端彼此相连
# 正因为有这个特性,veth-pair充当一个桥梁, 连接各种虚拟网络设备
# OpenStac, Docker容器之间的链接,OVS的链接, 都是使用veth-pair技术
  1. 我们测试一下 tomcat01 和 tomcat02 之间是否可以 ping 通!

    image-20230306234937390

结论:容器与容器之间是可以相互 ping 通的!

绘制一个网络模型图

在这里插入图片描述

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

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

小结

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

在这里插入图片描述

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

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

image-20230306235257734

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

1
2
3
4
# 通过--link解决网络连通问题
$ docker run -d -P --name tomcat03 --link tomcat02 tomcat

# 不可反向连接

image-20230307222308558

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

1
2
3
4
5
6
7
8
9
bayyy@bayzju ~/D/t/dockerfile> docker exec -it tomcat3 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 tomcat2 8d3440614a4d
172.17.0.4 5187b6165c5f

本质探究:—link 就是我们在 hosts 配置中增加了一个 172.17.0.3 tomcat02 f22ed47ed1be

我们现在玩 Docker 已经不建议使用—link 了!

自定义网络!不使用 Docker0!

Docker0 的问题:它不支持容器名链接访问!

  1. 自定义网络

查看所有的 docker 网络

在这里插入图片描述

2.1 网络模式

bridge: 桥接模式,桥接 docker 默认,自己创建的也是用 brdge 模式

none: 不配置网络

host: 和宿主机共享网络

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

测试

1
2
3
4
5
6
7
8
9
10
11
12
# 我们直接启动的命令默认有一个 --net bridge,而这个就是我们的docker0
# docker0特点,默认,容器名不能访问, --link可以打通连接!
$ docker run -d -P --name tomcat01 tomcat
# === #
$ docker run -d -P --name tomcat01 --net bridge tomcat

# 我们可以自定义一个网络!
# --driver bridge
# --subnet 192.168.0.0/16 可以支持255*255个网络 192.168.0.2 ~ 192.168.255.254
# --gateway 192.168.0.1
$ docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
3b33978f9ab5b17f74588c6eaa135854311ec8540f887d23148f98058b5e9cb8

我们自己创建的网络就 ok 了!

image-20230307224102410

在自己创建的网络里面启动两个容器

1
$ docker run -d -P --name tomcat01 --net mynet tomcat

image-20230307224344401

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

image-20230307224653336

2.2 好处

  • 可以直接通过容器名进行网络连接
  • 不同的集群使用不同的网络,保证集群时安全和健康的
  1. 网络连通

docker network connect net_name container_name

测试打通 tomcat01 和 mynet

在这里插入图片描述

1
2
3
4
$ docker network connect  mynet tomcat01
# 连通之后就是讲tomcat01 放到了mynet网路下
# 一个容器两个ip地址:
# 阿里云服务器,公网ip,私网ip

image-20230307225151765

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

实战:部署 redis

在这里插入图片描述

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# 创建网卡
$ 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

# 创建结点1
docker run -p 6371:6379 -p 16371:16379 --name redis-1 \
-v /mydata/redis/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

#创建结点2
docker run -p 6372:6379 -p 16372:16379 --name redis-2 \
-v /mydata/redis/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

#创建结点3
docker run -p 6373:6379 -p 16373:16379 --name redis-3 \
-v /mydata/redis/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

#创建结点4
docker run -p 6374:6379 -p 16374:16379 --name redis-4 \
-v /mydata/redis/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

#创建结点5
docker run -p 6375:6379 -p 16375:16379 --name redis-5 \
-v /mydata/redis/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

#创建结点6
docker run -p 6376:6379 -p 16376:16379 --name redis-6 \
-v /mydata/redis/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

# 创建集群
$ docker exec -it redis-1 sh

/data # ls
appendonly.aof nodes.conf/data
/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: cc5a49b7194d0e2bbdcd42b0e95c627b385ba131 172.38.0.11:6379
slots:[0-5460] (5461 slots) master
M: 5340b15d183bc1f796a1ce3160834fdcf12d80dd 172.38.0.12:6379
slots:[5461-10922] (5462 slots) master
M: 5a17af675024cdd64ed49f44af32ca15b817e8c4 172.38.0.13:6379
slots:[10923-16383] (5461 slots) master
S: ec889580288cae3604b0d7465098ed6fc26f7f02 172.38.0.14:6379
replicates 5a17af675024cdd64ed49f44af32ca15b817e8c4
S: fa0b3d67a933dec270c4de55d90acf5e5a876605 172.38.0.15:6379
replicates cc5a49b7194d0e2bbdcd42b0e95c627b385ba131
S: 3578dbbb21dca17960c584d17374ca12fedc5bd0 172.38.0.16:6379
replicates 5340b15d183bc1f796a1ce3160834fdcf12d80dd
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: cc5a49b7194d0e2bbdcd42b0e95c627b385ba131 172.38.0.11:6379
slots:[0-5460] (5461 slots) master
1 additional replica(s)
S: ec889580288cae3604b0d7465098ed6fc26f7f02 172.38.0.14:6379
slots: (0 slots) slave
replicates 5a17af675024cdd64ed49f44af32ca15b817e8c4
S: 3578dbbb21dca17960c584d17374ca12fedc5bd0 172.38.0.16:6379
slots: (0 slots) slave
replicates 5340b15d183bc1f796a1ce3160834fdcf12d80dd
S: fa0b3d67a933dec270c4de55d90acf5e5a876605 172.38.0.15:6379
slots: (0 slots) slave
replicates cc5a49b7194d0e2bbdcd42b0e95c627b385ba131
M: 5340b15d183bc1f796a1ce3160834fdcf12d80dd 172.38.0.12:6379
slots:[5461-10922] (5462 slots) master
1 additional replica(s)
M: 5a17af675024cdd64ed49f44af32ca15b817e8c4 172.38.0.13:6379
slots:[10923-16383] (5461 slots) master
1 additional replica(s)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

docker 搭建 redis 集群完成!

image-20230307231358825

SpringBoot 微服务打包 Docker 镜像

  1. 构建 springboot 项目

? IDEA2020 Ultimate 版本激活方案 亲测有效

  1. 打包应用

  2. 编写 Dockerfile

    FROM java:8 COPY *.jar /app.jarCMD [“—server.port=8080”] EXPOSE 8080 ENTRYPOINT [“java”, “-jar”, “/app.jar”]

  3. 构建镜像

  4. 发布运行!

    把打好的 jar 包和 Dockerfile 上传到 linux[root@iZ2zeg4ytp0whqtmxbsqiiZ idea]# lltotal 16140-rw-r—r— 1 root root 16519871 Aug 14 17:38 demo-0.0.1-SNAPSHOT.jar-rw-r—r— 1 root root 122 Aug 14 17:38 Dockerfile # 构建镜像,不要忘了最后有一个点[root@iZ2zeg4ytp0whqtmxbsqiiZ idea]# docker build -t xiaofan666 .Sending build context to Docker daemon 16.52MBStep 1/5 : FROM java:88: Pulling from library/java5040bd298390: 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:c1ff613e8ba25833d2e1940da0940c3824f03f802c449f3d1815a66b7f8c0e9dStatus: Downloaded newer image for java:8 —-> d23bdf5b1b1bStep 2/5 : COPY *.jar /app.jar —-> d4de8837ebf9Step 3/5 : CMD [“—server.port=8080”] —-> Running in e3abc66303f0Removing intermediate container e3abc66303f0 —-> 131bb3917feaStep 4/5 : EXPOSE 8080 —-> Running in fa2f25977db7Removing intermediate container fa2f25977db7 —-> d98147377951Step 5/5 : ENTRYPOINT [“java”, “-jar”, “/app.jar”] —-> Running in e1885e23773bRemoving intermediate container e1885e23773b —-> afb6b5f28a32Successfully built afb6b5f28a32Successfully tagged xiaofan666:latest # 查看镜像[root@iZ2zeg4ytp0whqtmxbsqiiZ idea]# docker imagesREPOSITORY TAG IMAGE ID CREATED SIZExiaofan666 latest afb6b5f28a32 14 seconds ago 660MBtomcat latest 2ae23eb477aa 8 days ago 647MBredis 5.0.9-alpine3.11 3661c84ee9d0 3 months ago 29.8MBjava 8 d23bdf5b1b1b 3 years ago 643MB # 运行容器[root@iZ2zeg4ytp0whqtmxbsqiiZ idea]# docker run -d -P —name xiaofan-springboot-web xiaofan666fd9a353a80bfd61f6930c16cd92204532bfd734e003f3f9983b5128a27b0375e# 查看运行起来的容器端口(因为我们启动的时候没有指定)[root@iZ2zeg4ytp0whqtmxbsqiiZ idea]# docker psCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMESfd9a353a80bf xiaofan666 “java -jar /app.jar …” 9 seconds ago Up 8 seconds 0.0.0.0:32779->8080/tcp xiaofan-springboot-web# 本地访问 1[root@iZ2zeg4ytp0whqtmxbsqiiZ idea]# curl localhost:32779{“timestamp”:”2020-08-14T09:42:57.371+00:00”,”status”:404,”error”:”Not Found”,”message”:””,”path”:”/“}# 本地访问 2[root@iZ2zeg4ytp0whqtmxbsqiiZ idea]# [root@iZ2zeg4ytp0whqtmxbsqiiZ idea]# curl localhost:32779/hellohello, xiaofan# 远程访问(开启阿里云上的安全组哦)

在这里插入图片描述

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

九,Docker Compose

Docker Compose

简介

Docker

Dockerfile build run 手动操作,单个容器!

微服务,100 个微服务,依赖关系。

Docker Compose 来轻松高效的管理容器,定义运行多个容器。

官方介绍

  1. 定义运行多个容器
  2. YAML file 配置文件
  3. single command。命令有哪些?

Compose is a tool for defining and running multi-container Docker applications. With Compose, you use a YAML file to configure your application’s services. Then, with a single command, you create and start all the services from your configuration. To learn more about all the features of Compose, see the list of features.

  1. 所有的环境都可以使用 compose。

Compose works in all environments: production, staging, development, testing, as well as CI workflows. You can learn more about each case in Common Use Cases.

三步骤:

Using Compose is basically a three-step process:

  1. Define your app’s environment with a Dockerfile so it can be reproduced anywhere.
    • Dockerfile 保证我们的项目再任何地方可以运行
  2. Define the services that make up your app in docker-compose.yml so they can be run together in an isolated environment.
    • services 什么是服务。
  3. Run docker-compose up and Compose starts and runs your entire app.
    • 启动项目

作用:批量容器编排

我自己的理解

Compose 是 Docker 官方的开源项目,需要安装!

Dockerfile让程序在任何地方运行。web 服务、redis、mysql、nginx… 多个容器。 run

Compose

version: '2.0'services:  web:    build: .    ports:    - "5000:5000"    volumes:    - .:/code    - logvolume01:/var/log    links:    - redis  redis:    image: redisvolumes:  logvolume01: {}

docker-compose up 100 个服务

Compose:重要概念

  • 服务 services, 容器、应用(web、redis、mysql…)
  • 项目 project。 一组关联的容器

安装

  1. 下载

    官网提供 (没有下载成功)curl -L “https://github.com/docker/compose/releases/download/1.26.2/docker-compose-$(uname -s)-$(uname -m)” -o /usr/local/bin/docker-compose # 国内地址 curl -L https://get.daocloud.io/docker/compose/releases/download/1.25.5/docker-compose-`uname -s-uname -m` > /usr/local/bin/docker-compose

  2. 授权

    chmod +x /usr/local/bin/docker-compose

在这里插入图片描述

体验(没有测试通过)

地址:https://docs.docker.com/compose/gettingstarted/

python 应用。 计数器。redis!

  1. 应用 app.py

  2. Dockerfile 应用打包为镜像

    FROM python:3.6-alpineADD . /codeWORKDIR /codeRUN pip install -r requirements.txtCMD ["python", "app.py"] # 官网的用来flask框架,我们这里不用它# 这告诉Docker# 从python3.7开始构建镜像# 将当前目录添加到/code印像中的路径中# 将工作目录设置为/code# 安装Python依赖项# 将容器的默认命令设置为python app.py
    
  3. Docker-compose yaml 文件(定义整个服务,需要的环境 web、redis) 完整的上线服务!

    version: '3.8'services:  web:    build: .    ports:      - "5000:5000"    volumes:      - .:/code  redis:    image: "redis:alpine"
    
  4. 启动 compose 项目 (docker-compose up)

流程:

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

yaml 规则

docker-compose.yaml 核心!

https://docs.docker.com/compose/compose-file/#compose-file-structure-and-examples

开源项目:博客

https://docs.docker.com/compose/wordpress/

下载程序、安装数据库、配置….

compose 应用 => 一键启动

  1. 下载项目(docker-compse.yaml)
  2. 如果需要文件。Dockerfile
  3. 文件准备齐全,一键启动项目即可

在这里插入图片描述

实战:自己编写微服务上线

  1. 编写项目微服务

  2. Dockerfile 构建镜像

    FROM java:8 COPY *.jar /app.jarCMD ["--server.port=8080"] EXPOSE 8080 ENTRYPOINT ["java", "-jar", "/app.jar"]
    
  3. docker-compose.yml 编排项目

    version '3.8'services:  xiaofanapp:    build: .    image: xiaofanapp    depends_on:      - redis    ports:      - "8080:8080"   redis:    image: "library/redis:alpine"
    
  4. 丢到服务器运行 docker-compose up

    docker-compose down # 关闭容器 docker-compose up —build # 重新构建

在这里插入图片描述

在这里插入图片描述

总结:

工程、服务、容器

项目 compose: 三层

  • 工程 Project
  • 服务
  • 容器 运行实例! docker k8s 容器

十,Docker Swarm

Docker Swarm

集群

购买服务器

  1. 登录阿里云账号,进入控制台,创建实例

    4台服务器2G
    

在这里插入图片描述

加粗样式

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

到此,我们的服务器购买成功!

四台机器安装 docker

和我们单机安装一样

技巧: xshell 直接同步操作,省时间!

Swarm 集群搭建

  • 工作机制

    在这里插入图片描述

    docker swarm init —help ip addr # 获取自己的 ip(用内网的不要流量) [root@iZ2ze58v8acnlxsnjoulk5Z ~]# docker swarm init —advertise-addr 172.16.250.97Swarm initialized: current node (otdyxbk2ffbogdqq1kigysj1d) is now a manager. To add a worker to this swarm, run the following command: docker swarm join —token SWMTKN-1-3vovnwb5pkkno2i3u2a42yrxc1dk51zxvto5hrm4asgn37syfn-0xkrprkuyyhrx7cidg381pdir 172.16.250.97:2377 To add a manager to this swarm, run ‘docker swarm join-token manager’ and follow the instructions.

初始化结点docker swarm init

docker swarm join 加入一个结点!

# 获取令牌docker swarm join-token managerdocker swarm join-token worker

[root@iZ2ze58v8acnlxsnjoulk6Z ~]# docker swarm join --token SWMTKN-1-3vovnwb5pkkno2i3u2a42yrxc1dk51zxvto5hrm4asgn37syfn-0xkrprkuyyhrx7cidg381pdir 172.16.250.97:2377This node joined a swarm as a worker.

把后面的结点都搭建进去

在这里插入图片描述

100 台!

  1. 生成主节点 init
  2. 加入(管理者,worker)

Raft 协议

双主双从:假设一个结点挂了!其他结点是否可以用!

Raft 协议:保证大多数结点存活才可以使用,只要>1, 集群至少大于 3 台!

实验:

1、将 docker1 机器停止。宕机!双主,另外一个结点也不能使用了!

在这里插入图片描述

  1. 可以将其他结点离开docker swarm leave

在这里插入图片描述

  1. worker 就是工作的,管理结点操作! 3 台结点设置为了管理结点。
  2. Docker swarm 集群增加节点

十分简单:集群,可用! 3 个主节点。 > 1 台管理结点存活!

Raft 协议:保证大多数结点存活,才可以使用,高可用!

体会

弹性、扩缩容!集群!

以后告别 docker run!

docker-compose up!启动一个项目。单机!

集群: swarm docker-service

k8s service

容器 => 服务!

容器 => 服务! => 副本!

redis => 10 个副本!(同时开启 10 个 redis 容器)

体验:创建服务、动态扩容服务、动态更新服务

在这里插入图片描述

  • 灰度发布(金丝雀发布)

    docker run 容器启动! 不具有扩缩容器 docker service 服务! 具有扩缩容器,滚动更新!

查看服务

在这里插入图片描述

动态扩缩容

[root@iZ2ze58v8acnlxsnjoulk5Z ~]# docker service update --replicas 3 my-nginx1/3: running   [==================================================>] 1/3: running   [==================================================>] 2/3: running   [==================================================>] 3/3: running   [==================================================>] verify: Service converged   [root@iZ2ze58v8acnlxsnjoulk5Z ~]# docker service scale my-nginx=5my-nginx scaled to 5overall progress: 3 out of 5 tasks overall progress: 3 out of 5 tasks overall progress: 3 out of 5 tasks overall progress: 5 out of 5 tasks 1/5: running   [==================================================>] 2/5: running   [==================================================>] 3/5: running   [==================================================>] 4/5: running   [==================================================>] 5/5: running   [==================================================>] verify: Service converged   [root@iZ2ze58v8acnlxsnjoulk5Z ~]# docker service scale my-nginx=1my-nginx scaled to 1overall progress: 1 out of 1 tasks 1/1: running   [==================================================>] verify: Service converged

移出!docker service rm

docker swarm 其实并不难

只要会搭建集群、会启动服务、动态管理容器就可以了!

概念的总结

swarm

集群的管理和编号,docker 可以初始化一个 swarm 集群,其他结点可以加入。(管理,工作者)

Node

就是一个 docker 结点,多个结点就组成了一个网络集群(管理、工作者)

Service

任务,可以在管理结点或者工作结点来运行。核心,用户访问。

Task

容器内的命令、细节任务!

在这里插入图片描述

service

在这里插入图片描述

命令 -> 管理 -> api -> 调度 -> 工作结点(创建 Task 容器维护创建!)

服务副本和全局服务

在这里插入图片描述

调整 service 以什么方式运行

--mode string                        Service mode (replicated or global) (default "replicated") docker service create --mode replicated --name mytom tomcat:7 默认的docker service create --mode global  --name haha alpine ping www.baidu.com

拓展: 网络模式 “PublishMode”:”ingress”

Swarm:

Overlay:

ingress:特殊的 Overlay 网络!负载均衡的功能!ipvs vip!

[root@iZ2ze58v8acnlxsnjoulk5Z ~]# docker network lsNETWORK ID          NAME                DRIVER              SCOPE74cecd37149f        bridge              bridge              local168d35c86dd5        docker_gwbridge     bridge              local2b8f4eb9c2e5        host                host                localdmddfc14n7r3        ingress             overlay             swarm8e0f5f648e69        none                null                local  [root@iZ2ze58v8acnlxsnjoulk5Z ~]# docker network inspect ingress[    {        "Name": "ingress",        "Id": "dmddfc14n7r3vms5vgw0k5eay",        "Created": "2020-08-17T10:29:07.002315919+08:00",        "Scope": "swarm",        "Driver": "overlay",        "EnableIPv6": false,        "IPAM": {            "Driver": "default",            "Options": null,            "Config": [                {                    "Subnet": "10.0.0.0/24",                    "Gateway": "10.0.0.1"                }            ]        },        "Internal": false,        "Attachable": false,        "Ingress": true,        "ConfigFrom": {            "Network": ""        },        "ConfigOnly": false,        "Containers": {            "ingress-sbox": {                "Name": "ingress-endpoint",                "EndpointID": "9d6ec47ec8309eb209f4ff714fbe728abe9d88f9f1cc7e96e9da5ebd95adb1c4",                "MacAddress": "02:42:0a:00:00:02",                "IPv4Address": "10.0.0.2/24",                "IPv6Address": ""            }        },        "Options": {            "com.docker.network.driver.overlay.vxlanid_list": "4096"        },        "Labels": {},        "Peers": [            {                "Name": "cea454a89163",                "IP": "172.16.250.96"            },            {                "Name": "899a05b64e09",                "IP": "172.16.250.99"            },            {                "Name": "81d65a0e8c03",                "IP": "172.16.250.97"            },            {                "Name": "36b31096f7e2",                "IP": "172.16.250.98"            }        ]    }]

其他命令学习方式

  • Docker Stack

    docker-compose 单机部署项目 docker stack 集群部署 # 单机 docker-compose up -d wordpress.yaml# 集群 docker stack deploy wordpress.yaml

  • Docker Secret

    安全!配置密码!证书! [root@iZ2ze58v8acnlxsnjoulk5Z ~]# docker secret —help Usage: docker secret COMMAND Manage Docker secrets Commands: create Create a secret from a file or STDIN as content inspect Display detailed information on one or more secrets ls List secrets rm Remove one or more secrets

  • Docker Config

    配置![root@iZ2ze58v8acnlxsnjoulk5Z ~]# docker config —help Usage: docker config COMMAND Manage Docker configs Commands: create Create a config from a file or STDIN inspect Display detailed information on one or more configs ls List configs rm Remove one or more configs

拓展到 k8s