docker入门

docker

概述

为什么会出现:

问题:我在我的电脑上可以运行!版本更新,导致服务不可用!

环境配置是十分麻烦的,每一个机器都要部署环境!费时费力

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

Docker的历史:

2010年,几个搞IT的年轻人,在美国成立了一家公司(dotCloud)(非常小型的公司)

做一些 pass 的云计算服务!Linux有关的容器技术!

他们将自己的技术 容器化技术命名 就是docker!

docker刚刚诞生的时候没有引起行业的注意!dotCloud,就活不下去!

开源:开发源代码

2013年,将docker开源!

docker越来越多的人发现了docker的优点!火了🔥🔥🔥,docker每个月都会更新一个版本!

2014年4月9日,docker 1.0发布

docker为什么这么🔥?十分的轻巧!

在容器技术之前,我们使用的都是虚拟机技术!

虚拟机:在win中安装VM ware(虚拟机软件),通过这个软件虚拟出一台或多台电脑!笨重!

虚拟机也是属于虚拟化技术,Docker容器技术也是一种虚拟化技术!

vm:linux centos 原生镜像(一台电脑!) 隔离:需要开启多个虚拟机 几个G 几分钟
docker :隔离,镜像(最核心的镜像 4m+ jdk +mysql)十分的小巧!运行镜像就可以了!小巧!几个M KB 秒级启动

到现在所有开发人员都必须要会docker!

聊一聊docker

docker是go语言开发的,

docker能干嘛

虚拟机技术缺点:

  • 资源占用十分多
  • 冗余步骤多
  • 启动慢

容器化技术

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

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

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

DevOps(开发、运维)

应用更快速的交付和部署

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

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

更便捷的升级和扩缩容

使用了Docker之后我们部署应用就和搭积木一样!

项目达成一个镜像,扩展 服务器A! 服务器B

更见的系统运维

在容器化之后我们的开发和运维是高度一致的

更高效的计算机资源利用

Docker是内核级别的虚拟化,可以在一个物理机上运行很多运行势力!服务器的性能会被使用到极致

只要学不死,就往死里学!

docker安装

docker的基本组成

镜像(image):

docker镜像就好比是一个模板,可以通过这个模板来创建容器服务

通过这个镜像可以创建多个容器(最终服务运行或者项目运行就是在容器中的)

容器(container):

docker利用容器技术,独立运行一个或者一个组应用,通过镜像来创建

目前就可以把这个容器理解为就是一个简易的linux系统

仓库(repository):

仓库就是存放镜像的地方!

仓库分为公有仓库和私有仓库!

Docker Hub(默认是国外的)

阿里云。。。都有镜像仓库(配置镜像加速)

安装Docker

环境准备

  1. 需要会一点点的Linux基础
  2. CentOS 7
  3. 我们使用Xshell,连接远程服务器进行操作

环境查看

#系统内核
[root@localhost ~]# uname -r
3.10.0-1160.88.1.el7.x86_64

#系统版本
[root@localhost ~]# 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"

安装

帮助文档

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

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

# 3. 设置镜像的仓库
sudo yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

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

# 4. 安装docker相关的
sudo yum install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

# 5. 启动docker
sudo  systemctl start docker

# 6. 查看docker是否安装成功
docker version

# 7. hello-world
docker run hello-world

# 8. 查看一下所有的镜像,包括hello-world
[root@localhost ~]# docker images
REPOSITORY    TAG       IMAGE ID       CREATED       SIZE
minio/minio   latest    b1241b0087e5   6 days ago    263MB
hello-world   latest    9c7a54a9a43c   5 weeks ago   13.3kB
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
  "data-root": "/data/docker",
  "registry-mirrors": ["https://w6360zl6.mirror.aliyuncs.com"]
}
EOF

sudo systemctl daemon-reload
sudo systemctl restart docker

了解:卸载docker

# 卸载依赖
 sudo yum remove docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin docker-ce-rootless-extras
# 删除资源
 sudo rm -rf /var/lib/docker 
 #/var/lib/docker  docker 的默认工作路径
 sudo rm -rf /var/lib/containerd

回顾hello-world

docker run的基本流程

在这里插入图片描述

底层原理

docker是怎么工作的?

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

docker serve接受的docker client的指令,就会执行这个命令!

docker为什么比虚拟机快?

  1. docker有着比虚拟机更少的抽象层

  2. docker利用的是宿主机的内核,vm需要的是Guest OS。

在这里插入图片描述

所以说,新建一个容器的使用,docker不需要像虚拟机一样从新加载一个操作系统内核,避免引导。虚拟机是加载Guest OS,分钟级别的,而docker是利用宿主机的操作系统,省略了这个复杂的过程,秒级!
在这里插入图片描述

之后学习完毕所有的命令,再回过头来看这段理会,就会很清晰!

docker的常用命令

帮助

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

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

镜像命令

docker images

[root@localhost containerd]# docker images
REPOSITORY    TAG       IMAGE ID       CREATED       SIZE
minio/minio   latest    b1241b0087e5   6 days ago    263MB
hello-world   latest    9c7a54a9a43c   5 weeks ago   13.3kB

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

可选项
  -a, --all             Show all images
  -q, --quiet           Only show image IDs

docker search搜索镜像

[root@localhost containerd]# docker search mysql
NAME                            DESCRIPTION                                     STARS     OFFICIAL   AUTOMATED
mysql                           MySQL is a widely used, open-source relation…   14206     [OK]      
mariadb                         MariaDB Server is a high performing open sou…   5428      [OK]  

# 可选项,通过搜索来过滤
--filter=STARS=3000 # 搜索出来的镜像就是STARS大于3000的
[root@localhost containerd]# docker search mysql --filter=STARS=3000
NAME      DESCRIPTION                                     STARS     OFFICIAL   AUTOMATED
mysql     MySQL is a widely used, open-source relation…   14206     [OK]       
mariadb   MariaDB Server is a high performing open sou…   5428      [OK] 

docker pull 下载镜像

# 下载镜像 docker pull 镜像名[:tag]
[root@localhost containerd]# docker pull mysql
Using default tag: latest             # 如果不写tag,默认就是 latest
latest: Pulling from library/mysql
3e0c3751e648: Pull complete           # 分层下载:docker image的核心 联合文件系统
7914193c6f0e: Pull complete 
fe4b3f820487: Pull complete 
63683b304e3d: Pull complete 
6ad9069836bd: Pull complete 
de90cd4c0e5d: Pull complete 
892e565e2cf0: Pull complete 
73057d123da0: Pull complete 
af1a3c0ec34e: Pull complete 
62fe8dc4ffe9: Pull complete 
8807488ae889: Pull complete 
Digest: sha256:4bae98614cd6ad1aecbdd32ff1b37b93fb0ee22b069469e7bc9679bacef1abd2 #签名
Status: Downloaded newer image for mysql:latest
docker.io/library/mysql:latest      # 真实地址

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

![img_4.png](img_4.png)

docker rmi 删除镜像

# 根据镜像id或镜像名称进行单个镜像删除
[root@localhost containerd]# docker rmi -f [镜像id]/[镜像名称:TAG]
# 删除多个镜像可以在镜像id或镜像名称之间添加空格
[root@localhost containerd]# docker rmi -f [镜像id]/[镜像名称:TAG] [镜像id]/[镜像名称:TAG] [镜像id]/[镜像名称:TAG]
# 删除全部的镜像,docker images -aq(查询出所有的镜像id)
[root@localhost containerd]# docker rmi -f $(docker images -aq)

可选项:
  -f 强制删除

容器命令

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

docker pull centos

新建容器并启动

docker run [可选参数] image

# 参数说明
  --name="Name" 容器名称 tomcate1 tomcate2,用来区分容器
  -d            后台方式运行
  -it            使用交互方式运行,进入容器查看内容
  -p            指定容器的端口 -p 8080:8080
  -p	   ip:主机端口:指定容器
    -p 指定容器
    容器端口
  -P            随机指定端口
  
#测试:启动并进入容器
[root@localhost containerd]# docker run -it centos /bin/bash
# 查看容器内的centos
[root@8199d7437c76 /]# ls
bin  etc   lib    lost+found  mnt  proc  run   srv  tmp  var dev  home  lib64  media       opt  root  sbin  sys  usr
# 从容器中退回主机
[root@8199d7437c76 /]# exit

列出所有运行的容器

docker ps 命令
        #列出当前正在运行的容器
  -a    #列出当前正在运行的容器+带出历史运行的容器
  -n=?  #显示最近创建的容器
  -q    #只显示容器的编号

[root@localhost /]# docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES
[root@localhost /]# docker ps -a
CONTAINER ID   IMAGE          COMMAND                  CREATED         STATUS                          PORTS     NAMES
8199d7437c76   centos         "/bin/bash"              2 minutes ago   Exited (0) About a minute ago             dreamy_mestorf
43ad5c34eb27   9c7a54a9a43c   "/hello"                 2 hours ago     Exited (0) 2 hours ago                    dreamy_shannon
af6d8789f293   b1241b0087e5   "/usr/bin/docker-ent…"   4 days ago      Exited (0) 3 days ago                     minio

退出容器

exit  # 直接停止容器退出

Ctrl + P + Q #容器不停止退出

删除容器

docker rm 容器id                    # 删除指定的容器,不能删除正在运行的容器,如果要强制删除,rm -f
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        # 强制停止当前容器

常用的其他命令

后台启动容器

# 命令 docker run -d 容器名
[root@localhost /]# docker run -d centos 停止了

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

# 常见的坑:docker 容器使用后台运行,就必须要有一个前台进程,docker发现没有应用了,就会自动停止
# nginx,容器启动后,发现自己没有提供服务,就会立刻停止,就是没有程序了

查看日志命令

docker logs -f -t --tail 容器,没有日志

# 自己编写一段shell脚本
[root@localhost /]# docker run -d centos /bin/sh -c "while true;do echo ceshishell;sleep 1;done"

[root@localhost /]# docker ps
CONTAINER ID   IMAGE     COMMAND                  CREATED              STATUS              PORTS     NAMES
2f6420ef2f72   centos    "/bin/sh -c 'while t…"   About a minute ago   Up About a minute             goofy_shtern

# 显示日志
[root@localhost /]# docker logs -tf --tail 20 2f6420ef2f72

# 参数
  -f / --follow     # 跟踪日志输出
  -t / --timestamps # 显示时间戳
  --tail / -n   [number]    # 从日志末尾显示的行数
  --until           # 在时间戳(例如)或相对时间戳(例如 42分钟)docker logs -f --until=2s 容器id
  --since           # 显示自时间戳(例如)或相对(例如 42分钟)
  --details         # 显示提供给日志的其他详细信息

查看容器中的进程信息 ps

# 命令 docker top 容器id
[root@localhost /]# docker top 2f6420ef2f72
UID                 PID                 PPID                C                   STIME               TTY                 TIME                CMD
root                3108                3089                0                   18:09               ?                   00:00:00            /bin/sh -c while true;do echo ceshishell;sleep 1;done
root                4089                3108                0                   18:23               ?                   00:00:00            /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 1

查看镜像的元数据

# 命令
docker inspect 容器id
# 测试
[root@localhost /]# docker inspect 2f6420ef2f72

docker_inspect .json

进入当前运行的容器

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

# 命令
docker exec -it 容器id 

# 测试
[root@localhost /]# docker ps
CONTAINER ID   IMAGE     COMMAND                  CREATED          STATUS          PORTS     NAMES
2f6420ef2f72   centos    "/bin/sh -c 'while t…"   21 minutes ago   Up 21 minutes             goofy_shtern
[root@localhost /]# docker exec -it 2f6420ef2f72 /bin/bash
[root@2f6420ef2f72 /]# ps -ef   
UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  0 10:09 ?        00:00:00 /bin/sh -c while true;do echo ceshishell;sleep 1;done
root      1297     0  0 10:30 pts/0    00:00:00 /bin/bash
root      1334     1  0 10:31 ?        00:00:00 /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 1
root      1335  1297  0 10:31 pts/0    00:00:00 ps -ef


# 方式二
docker attach 容器id

# 测试
[root@localhost /]# docker attach 2f6420ef2f72
正在执行当前的代码....

# docker exec     # 进入容器后开启一个新的终端,可以在里面进行操作
# docker attach   # 进入容器正在执行的终端,不会启动新的进程

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

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

[root@0c3f7d7fd44c home]# touch xuexi.java
[root@0c3f7d7fd44c home]# ls
xuexi.java
[root@0c3f7d7fd44c home]# exit
exit
[root@localhost community]# docker cp 0c3f7d7fd44c:/home/xuexi.java ./
                                               Successfully copied 1.54kB to /community/./
[root@localhost community]# ls
ceshi.java  data  doris  h5  index.html  jdk  minio  mysql  nacos  test.java  xuexi.java

#拷贝是一个手动过程,未来我们可以使用 -v卷的技术,可以实现

小结

在这里插入图片描述

NameDescription
attachAttach local standard input, output, and error streams to a running container当前shell 下attach 连接指定运行镜像
buildBuild an image from a Dockerfile通过Dockerfile定制镜像
builderManage builds管理生成
checkpointManage checkpoints管理检查点
commitCreate a new image from a container’s changes根据容器的更改创建新映像
configManage Swarm configs管理群配置
containerManage containers管理容器
contextManage contexts管理上下文
cpCopy files/folders between a container and the local filesystem在容器和本地文件系统之间复制文件/文件夹
createCreate a new container创建新容器
diffInspect changes to files or directories on a container’s filesystem检查对容器文件系统上的文件或目录的更改
eventsGet real time events from the server从服务器获取实时事件
execExecute a command in a running container在正在运行的容器中执行命令
exportExport a container’s filesystem as a tar archive将容器的文件系统导出为 tar 归档
historyShow the history of an image显示图像的历史记录
imageManage images管理图像
imagesList images列表图像
importImport the contents from a tarball to create a filesystem image从压缩包导入内容以创建文件系统映像
infoDisplay system-wide information显示系统范围的信息
inspectReturn low-level information on Docker objects返回有关 Docker 对象的低级信息
killKill one or more running containers终止一个或多个正在运行的容器
loadLoad an image from a tar archive or STDIN从 tar 存档或 STDIN 加载图像
loginLog in to a registry登录到注册表
logoutLog out from a registry从注册表注销
logsFetch the logs of a container获取容器的日志
manifestManage Docker image manifests and manifest lists管理 Docker 映像清单和清单列表
networkManage networks管理网络
nodeManage Swarm nodes管理群节点
pausePause all processes within one or more containers暂停一个或多个容器中的所有进程
pluginManage plugins管理插件
portList port mappings or a specific mapping for the container列出容器的端口映射或特定映射
psList containers列出容器
pullDownload an image from a registry从注册表下载映像
pushUpload an image to a registry将映像上传到注册表
renameRename a container重命名容器
restartRestart one or more containers重新启动一个或多个容器
rmRemove one or more containers删除一个或多个容器
rmiRemove one or more images删除一个或多个图像
runCreate and run a new container from an image从映像创建并运行新容器
saveSave one or more images to a tar archive (streamed to STDOUT by default)将一张或多张图像保存到 tar 存档(默认情况式传输到 STDOUT)
searchSearch Docker Hub for images在 Docker Hub 中搜索映像
secretManage Swarm secrets管理群机密
serviceManage Swarm services管理群服务
stackManage Swarm stacks管理群堆栈
startStart one or more stopped containers启动一个或多个已停止的容器
statsDisplay a live stream of container(s) resource usage statistics显示容器资源使用情况统计信息的实时流
stopStop one or more running containers停止一个或多个正在运行的容器
swarmManage Swarm管理群
systemManage Docker管理码头工人
tagCreate a tag TARGET_IMAGE that refers to SOURCE_IMAGE创建引用SOURCE_IMAGE的标记TARGET_IMAGE
topDisplay the running processes of a container显示容器正在运行的进程
trustManage trust on Docker images管理 Docker 映像上的信任
unpauseUnpause all processes within one or more containers取消暂停一个或多个容器中的所有进程
updateUpdate configuration of one or more containers更新一个或多个容器的配置
versionShow the Docker version information显示 Docker 版本信息
volumeManage volumes管理卷
waitBlock until one or more containers stop, then print their exit codes阻止,直到一个或多个容器停止,然后打印其退出代码

作业练习

Docker 安装nginx

# 1、搜索镜像 search	建议去dockerhub搜索,可以看到版本号
docker search nginx
# 2、下载镜像 pull
docker pull nginx
# 3、运行测试
[root@localhost community]# docker images
REPOSITORY   TAG       IMAGE ID       CREATED         SIZE
nginx        latest    f9c14fe76d50   2 weeks ago     143MB
centos       latest    5d0da3dc9764   21 months ago   231MB
# -d  后台运行
# --name 给容器命名
# -p 宿主机端口:容器内端口 宿主机端口映射到容器内端口
[root@localhost community]# docker run -d --name nginx01 -p 3344:80 nginx
4c7141c86a337b4ec343d7eb4a6069ffe03c189648898fc02e228139ac15f222
[root@localhost community]# docker ps
CONTAINER ID   IMAGE     COMMAND                  CREATED         STATUS         PORTS                                   NAMES
4c7141c86a33   nginx     "/docker-entrypoint.…"   9 seconds ago   Up 8 seconds   0.0.0.0:3344->80/tcp, :::3344->80/tcp   nginx01
[root@localhost community]# curl localhost:3344
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>
[root@localhost community]# docker exec -it 4c7141c86a33 /bin/bash
root@4c7141c86a33:/# whereis nginx
nginx: /usr/sbin/nginx /usr/lib/nginx /etc/nginx /usr/share/nginx

端口暴露概念

在这里插入图片描述

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

docker来安装tomcat

# 官方的建议
docker run -it --rm tomcat:9.0

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

# 下载启动
docker pull tomcat:9.0

# 启动运行
docker run -d -p 8080:8080 --name tomcat1 tomcat

# 测试访问没有问题

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

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

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

作业三:部署es+kibana

# es 暴露的端口很多!
# es 十分耗内存
# es 的数据一般需要放置到安全目录!挂载
# --net somenetwork ? 网络配置

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

# 启动了linux服务器就卡住了 docker stats 查看cpu的状态
# 启动成功
{
  "name" : "1eb6023a0d49",
  "cluster_name" : "docker-cluster",
  "cluster_uuid" : "lIeCUOsfRqmn5Yf87yK3Xw",
  "version" : {
    "number" : "7.6.2",
    "build_flavor" : "default",
    "build_type" : "docker",
    "build_hash" : "ef48eb35cf30adf4db14086e8aabd07ef6fb113f",
    "build_date" : "2020-03-26T06:34:37.794943Z",
    "build_snapshot" : false,
    "lucene_version" : "8.4.0",
    "minimum_wire_compatibility_version" : "6.8.0",
    "minimum_index_compatibility_version" : "6.0.0-beta1"
  },
  "tagline" : "You Know, for Search"
}
# es 是十分耗内存的1.XG 1核2G

# 查看cpu的内存状态
docker stats

CONTAINER ID   NAME            CPU %     MEM USAGE / LIMIT     MEM %     NET I/O     BLOCK I/O    PIDS
1eb6023a0d49   elasticsearch   139.61%   1.219GiB / 1.795GiB   67.95%    656B / 0B   259MB / 0B   20

# 赶紧关闭,增加内存限制,修改配置文件 -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

作业:使用kibana连接es,思考网络如何才能连接过去

可视化

  • 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图形界面管理工具!提供一个后台面板供我们使用!

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

访问测试:ip:8088

在这里插入图片描述
在这里插入图片描述

尽量少的使用可是画面版,平时玩玩就好

docker镜像讲解

镜像是什么?

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

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

如何得到镜像:

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

docker镜像加载原理

UnionFS(联合文件系统)

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

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

在这里插入图片描述

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

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

虚拟机时分钟级别,容器时秒级!

分层的理解

在这里插入图片描述

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

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

查看镜像分布的方式可以通过:

docker image inspect XXXX

.....
"RootFS": {
            "Type": "layers",
            "Layers": [
                "sha256:8cbe4b54fa88d8fc0198ea0cc3a5432aea41573e6a0ee26eca8c79f9fbfa40e3",
                "sha256:c09692444d6a69ba83a73793838331bde08955e12f8326f08cf5c5682cde737b",
                "sha256:4f4da5637d3e671c6886a3db04d5138d948adb69822a692d933641e43c40f31b",
                "sha256:20ca8f6f146cb03634370cc70ae8445727a7b798c40e99316dc1bee5e99e02b0",
                "sha256:1236e900cd78c7236b9c560ac7b0d5697f22e48d1f4217851431a92267009bd5",
                "sha256:1a20a5ac360fdfe5813cfde434adcd2f788e662175bdb9b179a3e813be89bea0"
            ]
        },
...

/var/lib/docker/image/overlay2/layerdb/sha256存储下载下来的镜像层,使所有镜像共用,Docker 镜像层使用了联合挂载 (Union Mount) 的机制,使用户查找的只有一个镜像。

理解:

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

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

该镜像当前已经包含3个镜像层,如下图所示(这只是一个用于演示的很简单的例子)

在额外的镜像层的同时,镜像始终保持是当前所有镜像的组合,理解这一点很重要。下图举了一个简单的例子,每个镜像层包含3个文件,而镜像包含了来自两个镜像层的6个文件

在这里插入图片描述

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

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

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

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

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

docker在windows上仅支持windowsfilter一种存储引擎,该引擎基于NTFS文件系统之上实现了分层和CoW[1]。

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

在这里插入图片描述

特点

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

这一层就是我们通常说的容器层,容器之下的都叫做镜像层。

在这里插入图片描述

镜像层实际上是存在 Docker 中的文件系统中的。在 Docker 的存储模型中,每个镜像层都是一个只读的文件系统,它们按照从基础镜像到当前镜像的构建顺序排列,最终组成了完整的容器文件系统。

当需要运行一个 Docker 容器时,Docker 容器引擎会根据容器的镜像信息在本地查找并加载对应的镜像层,然后将这些镜像层按照联合挂载 (Union Mount) 的方式组装成一个只读的联合文件系统 (UnionFS),作为容器的根文件系统。这样,由多个镜像层组成的容器文件系统将被挂载到容器中,从而为容器提供运行所需的完整文件系统环境。

镜像层实际上是以只读的形式存储在 Docker 的文件系统中,它们由多个存储了文件系统增量变化的 tarball 文件构成。当需要构建新的镜像时,Docker 会根据 Dockerfile 的描述和当前基础镜像的 ID,将新的 tarball 文件叠加在基础镜像的 tarball 上,从而构成新的镜像层。这种结构称为镜像层链 (image layer chain)。当需要使用某个镜像创建容器时,Docker 容器引擎会按照镜像层链的顺序逐层加载镜像层,并将其联合挂载成一个只读的联合文件系统。这意味着,最终容器运行所使用的文件系统实际上由多个镜像层共同组成,但对于容器内部来说,它看到的只是一层完整的文件系统,因为 Docker 容器引擎已经帮我们处理好了这些镜像层的加载和联合挂载问题。Docker 中的每个镜像都是一个单独的、完整的文件系统,在使用时无需考虑底层的镜像层链。

如何提交自己的镜像

commit镜像

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

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

实战测试:

# 1、启动一个默认的tomcat

# 2、发现这个默认的tomcat 是没有webapps应用,镜像的原因,官方的镜像默认webapps下面是没有文件的!

# 3、自己拷贝进去了基本文件

# 4、将我哦们操作过的容器通过commit命令推送为一个新的自定义镜像!我们以后就是用我们修改过的镜像即可,这就是我们自己的一个修改的镜像
 docker commit -a="Lucky" -m="commit test" 987cc6f670a9 tomcat_lucky:1.0

学习方法说明:理解概念,但是一定要实践,最后实践和理论相结合一次搞定这个知识

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

学到这里才算是入门docker

容器数据卷

什么是容器数据卷?

docker理念回顾

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

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

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

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

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

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

使用数据卷

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

docker run -it -v 主机目录:容器内目录 -p 主机端口:容器内端口 /bin/bash

# 启动之后可以通过docker inspect 容器id 来查看挂载信息

在这里插入图片描述

实战:安装MySQL

# 下载mysql镜像
[root@localhost ~]# docker pull mysql:5.7

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

# 启动我们的
-d 后台运行
-p 端口映射
-v 卷挂载
-e 环境配置
--name 容器名字
[root@localhost community]# docker run -d -p 3306:3306 -v /community/mysql/conf:/etc/mysql/conf.d -v /community/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=100%Wan5Yi10. --name mysql5.7 mysql:5.7
# 启动成功后可以使用navicat连接到容器中的mysql

假设我们把容器删除

发现,我们挂载到本地的数据卷依旧没有丢失,这就实现了容器持久化功能

具名和匿名挂载

# 匿名挂载
docker run -d -P --name nginx01 -v /etc/nginx nginx

# 查看所有的volume的情况
[root@localhost _data]# docker volume ls
DRIVER    VOLUME NAME
local     f686698656e0d0a5b5a283e505251cde74b9ebba32d1e268f5b973034a0d149d
# 这里发现,这种就是匿名挂在,我们在-v只写了容器内的路径,没有写容器外的路径!

# 具名挂载
[root@localhost _data]# docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx nginx
de2ebc2a87aa24503e65b5b6e44707ecbf51a07ce151d73b4ab06fdee1f0cae9
[root@localhost _data]# docker volume ls
DRIVER    VOLUME NAME
local     juming-nginx

# 通过 -v 卷名:容器内路径
# 查看一下这个卷
[root@localhost merged]# docker volume inspect juming-nginx
[
    {
        "CreatedAt": "2023-06-15T13:47:30+08:00",
        "Driver": "local",
        "Labels": null,
        "Mountpoint": "/community/docker/volumes/juming-nginx/_data",
        "Name": "juming-nginx",
        "Options": null,
        "Scope": "local"
    }
]

所有的docker容器内的卷,没有指定目录的情况下默认都是/docker/volumes/XXXXXx/_data

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

在这里插入图片描述

# 如何确定是具名挂载还是匿名挂载,还是指定路径挂载
-v 容器内路径	# 匿名挂载
-v 卷名:容器内路径		# 具名挂载
-v 本机路径:容器内路径	#指定路径挂在

扩展:

# 通过 -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就是用来构建docker镜像的构建文件!命令脚本!先体验一下!

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

# 创建一个dockerfile文件,名字可以随机取,建议 DockerFile
# 文件中的内容 指令(大写)参数
FROM centos

VOLUME ["volume01","volume02"]

CMD enco "----end----"
CMD /bin/bash
# 这里的每个命令都是一层

在这里插入图片描述
启动自己写的镜像

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

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

数据卷容器

多个mysql同步数据!

# 启动三个容器,通过

多个mysql实现数据共享

[root@localhost docker-test-volume]# docker run -d -p 3306:3306 -v /etc/mysql/conf.d -v /var/lib/mysql -e MYSQL_ROOT_PASSWORD=100%Wan5Yi10. --name mysql5.701 mysql:5.7

[root@localhost docker-test-volume]# docker run -d -p 3306:3306 -e MYSQL_ROOT_PASSWORD=100%Wan5Yi10. --volumes-from mysql5.701 --name mysql5.702 mysql:5.7

# 这是后,可以实现两个容器数据同步!

结论:

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

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

DockerFile

dockerFile介绍

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

构建步骤:

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

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

官方既然可以制作镜像,那么我们也可以!

DockerFile的构建过程

基础知识:

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

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

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

步骤:开发、部署、运维。。。缺一不可

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

DockerImage:通过DockerFile构建生成的一个镜像,最终发布和运行的产品,原来是一个jar war

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

DockerFile的指令

以前的话我们就是使用别人的,现在我们知道了这些命令后,我们来练习自己写一个镜像!

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

实战测试:

Docker Hub种99%的镜像都是从这个镜像过来的FROM scratch,然后配置需要的软件和配置来进行构建

创建一个自己的centos

# 1、编写DockerFile的文件
FROM centos:7
MAINTAINER QXK<15964709777@163.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 ./mydockerfile-centos -t mycentos:1.0 .

CMD 和 ENTRYPOINT的区别

CMD               # 指定这个容器启动的时候要运行的命令,只有最后一个会生效,可被替代
ENTRYPOINT        # 指定这个容器启动的时候要运行的命令,可以追加命令
测试cmd
[root@localhost dockerfile]# vim dockerfile-cmd-test 
FROM centos:7
CMD ["ls","-a"]
[root@localhost dockerfile]# docker build -f dockerfile-cmd-test -t cmdtest .

# run运行,发现我们的ls -a生效了
[root@localhost dockerfile]# docker run  6f578840252f 
.
..
.dockerenv
anaconda-post.log
bin
dev
etc
home
lib
lib64
media
mnt
opt
proc
root
run
sbin
srv
sys
tmp
usr
var
# 想追加一个命令 -l ls -al
[root@localhost dockerfile]# docker run  6f578840252f -l
docker: Error response from daemon: failed to create task for container: 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.

# cmd的清理下 -l 替换了 CMD ["ls","-a"] 命令,-l 不是命令所以报错
测试ENTRYPOINT
[root@localhost dockerfile]# vim dockerfile-entrypoint-test
FROM centos:7
ENTRYPOINT ["ls","-a"]
[root@localhost dockerfile]# docker build -f dockerfile-entrypoint-test -t entrypointtest .
DEPRECATED: The legacy builder is deprecated and will be removed in a future release.
            BuildKit is currently disabled; enable it by removing the DOCKER_BUILDKIT=0
            environment-variable.

Sending build context to Docker daemon   5.12kB
Step 1/2 : FROM centos:7
 ---> eeb6ee3f44bd
Step 2/2 : ENTRYPOINT ["ls","-a"]
 ---> Running in 9acbcff5d41c
Removing intermediate container 9acbcff5d41c
 ---> ee2cb4375235
Successfully built ee2cb4375235
Successfully tagged entrypointtest:latest
[root@localhost dockerfile]# docker run  ee2cb4375235
.
..
.dockerenv
anaconda-post.log
bin
dev
etc
home
lib
lib64
media
mnt
opt
proc
root
run
sbin
srv
sys
tmp
usr
var
# 我们追加的命令,是直接拼接在我们ENTRYPOINT命令的后面的
[root@localhost dockerfile]# docker run  ee2cb4375235 -l
total 12
drwxr-xr-x   1 root root     6 Jun 16 11:24 .
drwxr-xr-x   1 root root     6 Jun 16 11:24 ..
-rwxr-xr-x   1 root root     0 Jun 16 11:24 .dockerenv
-rw-r--r--   1 root root 12114 Nov 13  2020 anaconda-post.log
lrwxrwxrwx   1 root root     7 Nov 13  2020 bin -> usr/bin
drwxr-xr-x   5 root root   340 Jun 16 11:24 dev
drwxr-xr-x   1 root root    66 Jun 16 11:24 etc
drwxr-xr-x   2 root root     6 Apr 11  2018 home
lrwxrwxrwx   1 root root     7 Nov 13  2020 lib -> usr/lib
lrwxrwxrwx   1 root root     9 Nov 13  2020 lib64 -> usr/lib64
drwxr-xr-x   2 root root     6 Apr 11  2018 media
drwxr-xr-x   2 root root     6 Apr 11  2018 mnt
drwxr-xr-x   2 root root     6 Apr 11  2018 opt
dr-xr-xr-x 117 root root     0 Jun 16 11:24 proc
dr-xr-x---   2 root root   114 Nov 13  2020 root
drwxr-xr-x  11 root root   148 Nov 13  2020 run
lrwxrwxrwx   1 root root     8 Nov 13  2020 sbin -> usr/sbin
drwxr-xr-x   2 root root     6 Apr 11  2018 srv
dr-xr-xr-x  13 root root     0 Jun 16 11:24 sys
drwxrwxrwt   7 root root   132 Nov 13  2020 tmp
drwxr-xr-x  13 root root   155 Nov 13  2020 usr
drwxr-xr-x  18 root root   238 Nov 13  2020 var

DockerFile中很多命令都十分相似,我们需要了解他们的区别,我们最好的学习就是比对他们然后测试

实战:Tomcat镜像

  1. 准备镜像文件 tomcat压缩包 ,jdk的压缩包
    在这里插入图片描述
  2. 编写dockerfile文件,官方命名Dockerfile,命名为Dockerfile,build时可以不-f指定dockerfile文件,会默认去找名为Dockerfile的文件
FROM centos:7.9.2009
MAINTAINER qxk<15964709777@163.com>

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

ADD jdk-8u202-linux-x64.tar.gz /usr/local/
ADD apache-tomcat-9.0.76.tar.gz /usr/local/

RUN yum install -y vim

ENV MTPATH /usr/local
WORKDIR $MTPATH

ENV JAVA_HOME /usr/local/jdk1.8.0_202
ENV CLASS_PATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.76
ENV CATALINA_BASH /usr/local/apache-tomcat-9.0.76
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin

EXPOSE 8080

CMD /usr/local/apache-tomcat-9.0.76/bin/startup.sh  && tail -F /usr/local/apache-tomcat-9.0.76/logs/catalina.out
FROM centos:7.9.2009
MAINTAINER qxk<15964709777@163.com>

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

# 创建 tomcat用户
RUN groupadd -r tomcat && useradd -r -g tomcat -d /opt/tomcat -s /sbin/nologin -c "Tomcat user" tomcat

# 下载 Tomcat 安装包 (这里以 Tomcat 9.0.50 为例)
ADD https://downloads.apache.org/tomcat/tomcat-9/v9.0.76/bin/apache-tomcat-9.0.76.tar.gz /usr/local/

# 解压 Tomcat 安装包到 /opt/tomcat 目录下
RUN tar xvzf /usr/local/apache-tomcat-9.0.76.tar.gz -C /opt/ && mv /opt/apache-tomcat-9.0.76 /opt/tomcat && chown -R tomcat:tomcat /opt/tomcat

ADD jdk-8u202-linux-x64.tar.gz /usr/local/

ENV CATALINA_HOME /opt/tomcat
WORKDIR $CATALINA_HOME

ENV JAVA_HOME /usr/local/jdk1.8.0_202
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV PATH $PATH:$CATALINA_HOME/bin:$JAVA_HOME/bin

EXPOSE 8080
CMD ["catalina.sh", "run"]
  1. 构建镜像
# docker build -f [dockerfile的文件名,如果为Dockerfile则可以不是用-f指定] -t 镜像名:tag .
docker build -t diytomcat:1.0 .
[root@localhost tomcat]# docker images
REPOSITORY        TAG       IMAGE ID       CREATED          SIZE
diytomcat         1.0       8e7b8f1f1559   26 minutes ago   887MB
  1. 启动自定义镜像,一定要-d
docker run -d -p 9090:8080 \
-v /community/dockerfile/tomcat/test/webapps:/usr/local/apache-tomcat-9.0.76/webapps/test \
-v /community/dockerfile/tomcat/test/logs:/usr/local/apache-tomcat-9.0.76/logs \
--name luckytomcat diytomcat:1.0

[root@localhost tomcat]# docker run -d -p 9090:8080 \
> -v /community/dockerfile/tomcat/test/webapps:/usr/local/apache-tomcat-9.0.76/webapps/test \
> -v /community/dockerfile/tomcat/test/logs:/usr/local/apache-tomcat-9.0.76/logs \
> --name luckytomcat diytomcat:1.0
  1. 访问测试
  2. 发布项目(由于做了卷挂载,我们直接再本地编写项目就可以)
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" 
		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
		xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
		http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" id="WebApp_ID" version="4.0">

</web-app>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>菜鸟教程(runoob.com)</title>
</head>
<body>

<h2>include 动作实例</h2>

</body>
</html>

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

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

发布自己的镜像

阿里云镜像服务

1、地址容器镜像服务 (aliyun.com)

2、确定这个账号可以登录,找到容器镜像服务,创建命名空间,创建容器镜像

在这里插入图片描述
3、在我们的服务其上提交自己的镜像

[root@localhost webapps]# docker login --help

Usage:  docker login [OPTIONS] [SERVER]

Log in to a 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

[root@localhost webapps]# docker login --username=qxk15964709777 registry.cn-hangzhou.aliyuncs.com
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
docker tag [ImageId] registry.cn-hangzhou.aliyuncs.com/luckyqxk/newbox:[镜像版本号]

阿里云容器镜像的就参考官方地址!

网站开源!

Docker网络

理解网络Docker0

# 清空所有容器
docker rm -f $(docker ps -aq)
docker ps -aq|xargs docker rm -f 

# 清空所有镜像
docker rmi -f $(docker images -aq)
docker images -aq|xargs docker rmi -f

# 清空docker缓存
docker system prune

lo:本机回环地址

enp0s3:NAT网卡

enp0s8:host-only网卡

docker0

三个网络

# 问题:docker是如何处理容器网络访问的?
# [root@localhost docker]# docker run -d -P --name mycentos centos:7.9.2009
# [root@localhost docker]# docker exec -it mycentos /bin/bash
# [root@b866c8ab3847 /]# yum install -y iproute

# 查看容器的内部网络地址 ip addr ,发现容器启动的时候会获得一个eth0@if22 ip地址 
[root@b866c8ab3847 /]# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
21: eth0@if22: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:ac:11:00:04 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 172.17.0.4/16 brd 172.17.255.255 scope global eth0
       valid_lft forever preferred_lft forever
# 思考,linux能不能ping通容器内部!
[root@localhost tomcat]# ping 172.17.0.4
PING 172.17.0.4 (172.17.0.4) 56(84) bytes of data.
64 bytes from 172.17.0.4: icmp_seq=1 ttl=64 time=0.762 ms
64 bytes from 172.17.0.4: icmp_seq=2 ttl=64 time=0.047 ms
64 bytes from 172.17.0.4: icmp_seq=3 ttl=64 time=0.081 ms
^C
--- 172.17.0.4 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 1999ms
rtt min/avg/max/mdev = 0.047/0.296/0.762/0.329 ms

# linux可以ping通docker容器内部

原理

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

桥接模式,使用的技术是evth-part技术!

再次测试

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

2、我们来测试一个两个docker容器之间是可以ping通的

[root@localhost tomcat]# docker exec -it b866c8ab3847 ping 172.17.0.4
# 结论,容器和容器之间是可以ping通的

网络请求图:

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

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

小结

Docker使用的linux桥接,通过veth-pair技术,宿主机是一个Docker容器的网桥,docker0

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

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

–link

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

[root@localhost tomcat]# docker exec -it tomcat01 ping luckytomcat
ping: luckytomcat: Name or service not known
# 如何可以解决

# 通过--link可以解决网络连通问题
[root@localhost tomcat]# docker run -d -P --name tomcat02 --link tomcat01  diytomcat:1.0
c6123fc073b0c42f7668f651d039bb960675801f31d526a8418f0189676f3894
[root@localhost tomcat]# docker exec -it tomcat02 ping tomcat01
PING tomcat01 (172.17.0.2) 56(84) bytes of data.
64 bytes from tomcat01 (172.17.0.2): icmp_seq=1 ttl=64 time=0.190 ms
64 bytes from tomcat01 (172.17.0.2): icmp_seq=2 ttl=64 time=0.055 ms
64 bytes from tomcat01 (172.17.0.2): icmp_seq=3 ttl=64 time=0.067 ms
64 bytes from tomcat01 (172.17.0.2): icmp_seq=4 ttl=64 time=0.061 ms
64 bytes from tomcat01 (172.17.0.2): icmp_seq=5 ttl=64 time=0.069 ms
64 bytes from tomcat01 (172.17.0.2): icmp_seq=6 ttl=64 time=0.069 ms

--- tomcat01 ping statistics ---
6 packets transmitted, 6 received, 0% packet loss, time 4999ms
rtt min/avg/max/mdev = 0.055/0.085/0.190/0.047 ms

# 反向这边可以ping通吗
[root@localhost tomcat]# docker exec -it tomcat01 ping tomcat02
ping: tomcat02: Name or service not known

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

本质探究:–link 就是我们在hosts配置中添加了一个172.17.0.2 tomcat01 b0eb8517261e

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

自定义网络!不适用docker0!

docker0问题:它不支持容器名连接访问!

自定义网络

查看所有的docker网络

网络模式

bridge:桥接模式,通过docker0实现容器间网络互通(默认,自己创建也是使用桥接)

none:不配置网络

host:和宿主机共享网络

container:容器网络互联!(用的少,局限性很大)

测试:

# 我们直接启动的命令 --net bridge
[root@localhost ~]# docker run -d -P --name tomcat01 --net bridge diytomcat:1.0

# 我们可以自定义一个网络
# --driver bridge 
# --subnet 192.168.0.0/16 
# --gateway 192.168.0.1
[root@localhost ~]# docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
9bbbec8ba13c0ee8c5168ca102effe5dd5d0578ad2324581ca60b54e3678b65b
[root@localhost ~]# docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
9b25f8f2f8bf   bridge    bridge    local
206b08ec16db   host      host      local
9bbbec8ba13c   mynet     bridge    local
7b055a911340   none      null      local

我们自己的网络就创建好了

[root@localhost ~]# docker run -d -P --name tomcat01 --net mynet diytomcat:1.0
95db021f277f5ee0934e355b4f9ff0a3d4996e2b86be9ac57c6d8565a7dde154
[root@localhost ~]# docker run -d -P --name tomcat02 --net mynet diytomcat:1.0
53a91247665341fa0bba17c55de77f1c4c2b000c03e2ed6296b97665a020e5ea
[root@localhost ~]# docker network inspect mynet
[
    {
        "Name": "mynet",
        "Id": "9bbbec8ba13c0ee8c5168ca102effe5dd5d0578ad2324581ca60b54e3678b65b",
        "Created": "2023-07-05T10:43:53.363413514+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": {
            "53a91247665341fa0bba17c55de77f1c4c2b000c03e2ed6296b97665a020e5ea": {
                "Name": "tomcat02",
                "EndpointID": "2ca87cbb18bf01c9cb9dceba483989e55077812e52b856291d9359be6a18ff71",
                "MacAddress": "02:42:c0:a8:00:03",
                "IPv4Address": "192.168.0.3/16",
                "IPv6Address": ""
            },
            "95db021f277f5ee0934e355b4f9ff0a3d4996e2b86be9ac57c6d8565a7dde154": {
                "Name": "tomcat01",
                "EndpointID": "9648681fda8773dd17e84b5de845086ec6d21d3f4f3c23a18cc99485dea91b18",
                "MacAddress": "02:42:c0:a8:00:02",
                "IPv4Address": "192.168.0.2/16",
                "IPv6Address": ""
            }
        },
        "Options": {},
        "Labels": {}
    }
]
[root@localhost ~]# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 08:00:27:19:ed:5f brd ff:ff:ff:ff:ff:ff
    inet 10.0.2.15/24 brd 10.0.2.255 scope global noprefixroute dynamic enp0s3
       valid_lft 83886sec preferred_lft 83886sec
    inet6 fe80::5466:49a3:2208:4f6a/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever
3: enp0s8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 08:00:27:a5:49:97 brd ff:ff:ff:ff:ff:ff
    inet 192.168.137.92/24 brd 192.168.137.255 scope global noprefixroute enp0s8
       valid_lft forever preferred_lft forever
    inet6 fe80::febb:5e88:8533:9beb/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever
4: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default 
    link/ether 02:42:1f:c8:73:83 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:1fff:fec8:7383/64 scope link 
       valid_lft forever preferred_lft forever
15: br-9bbbec8ba13c: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:c5:91:ab:ec brd ff:ff:ff:ff:ff:ff
    inet 192.168.0.1/16 brd 192.168.255.255 scope global br-9bbbec8ba13c
       valid_lft forever preferred_lft forever
    inet6 fe80::42:c5ff:fe91:abec/64 scope link 
       valid_lft forever preferred_lft forever
17: vethbdcdde3@if16: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master br-9bbbec8ba13c state UP group default 
    link/ether ce:eb:0f:c8:ef:f6 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet6 fe80::cceb:fff:fec8:eff6/64 scope link 
       valid_lft forever preferred_lft forever
19: veth73e56aa@if18: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master br-9bbbec8ba13c state UP group default 
    link/ether e6:ae:f6:0f:fd:fd brd ff:ff:ff:ff:ff:ff link-netnsid 1
    inet6 fe80::e4ae:f6ff:fe0f:fdfd/64 scope link tentative 
       valid_lft forever preferred_lft forever

# 再次测试ping连接
# 现在不使用--link也可以实现通过容器名连接
[root@localhost ~]# docker exec -it tomcat01 ping tomcat02
PING tomcat02 (192.168.0.3) 56(84) bytes of data.
64 bytes from tomcat02.mynet (192.168.0.3): icmp_seq=1 ttl=64 time=2.76 ms
64 bytes from tomcat02.mynet (192.168.0.3): icmp_seq=2 ttl=64 time=0.085 ms
64 bytes from tomcat02.mynet (192.168.0.3): icmp_seq=3 ttl=64 time=0.066 ms
64 bytes from tomcat02.mynet (192.168.0.3): icmp_seq=4 ttl=64 time=0.077 ms
64 bytes from tomcat02.mynet (192.168.0.3): icmp_seq=5 ttl=64 time=0.058 ms
^C
--- tomcat02 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4002ms
rtt min/avg/max/mdev = 0.058/0.611/2.769/1.079 ms
[root@localhost ~]# docker exec -it tomcat02 ping tomcat01
PING tomcat01 (192.168.0.2) 56(84) bytes of data.
64 bytes from tomcat01.mynet (192.168.0.2): icmp_seq=1 ttl=64 time=0.970 ms
64 bytes from tomcat01.mynet (192.168.0.2): icmp_seq=2 ttl=64 time=0.390 ms
64 bytes from tomcat01.mynet (192.168.0.2): icmp_seq=3 ttl=64 time=0.244 ms
64 bytes from tomcat01.mynet (192.168.0.2): icmp_seq=4 ttl=64 time=0.394 ms
64 bytes from tomcat01.mynet (192.168.0.2): icmp_seq=5 ttl=64 time=0.214 ms
^C
--- tomcat01 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4003ms
rtt min/avg/max/mdev = 0.214/0.442/0.970/0.274 ms

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

好处:

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

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

网络连通

在这里插入图片描述
在这里插入图片描述

# 测试打通 tomcat-docker01  与tomcat01
# 连通之后就是将tomcat-docker01 放到了 mynet网络下
# 一个容器两个ip
# 阿里云服务,公网地址ip,内网地址ip
# 连通ok
[root@localhost ~]# docker exec -it tomcat-docker01 ping tomcat01
PING tomcat01 (192.168.0.2) 56(84) bytes of data.
64 bytes from tomcat01.mynet (192.168.0.2): icmp_seq=1 ttl=64 time=0.365 ms
64 bytes from tomcat01.mynet (192.168.0.2): icmp_seq=2 ttl=64 time=0.407 ms
64 bytes from tomcat01.mynet (192.168.0.2): icmp_seq=3 ttl=64 time=0.108 ms
^C
--- tomcat01 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 1998ms
rtt min/avg/max/mdev = 0.108/0.293/0.407/0.132 ms

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

实战:部署redis集群

shell脚本!

# 创建网卡
docker network create redis --subnet 172.38.0.0/16

# 通过shell脚本创建6个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
docker run -p 637${port}:6379 -p 1637${port}:16379 --name redis-${port} \
-v /mydata/redis/node-${port}/data:/data \
-v /mydata/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

docker run -p 637${port}:6379 -p 1637${port}:16379 --name redis-${port} \
-v /mydata/redis/node-${port}/data:/data \
-v /mydata/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; \

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

# 创建集群 
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

/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: 9e2c4fbebec08cd915bec1ba631a3010e724a10e 172.38.0.11:6379
   slots:[0-5460] (5461 slots) master
M: 8ed940e6e4b57e9913cbe83d6a86beb4068860c2 172.38.0.12:6379
   slots:[5461-10922] (5462 slots) master
M: a9f74adc02e988dbfd611ed3e76d0907487fcea6 172.38.0.13:6379
   slots:[10923-16383] (5461 slots) master
S: b6d34800dc58703e4efd2175cacdf3599ff5c8a6 172.38.0.14:6379
   replicates a9f74adc02e988dbfd611ed3e76d0907487fcea6
S: 0035700b84f47b4898537eae4fc2dd531eb9a0dd 172.38.0.15:6379
   replicates 9e2c4fbebec08cd915bec1ba631a3010e724a10e
S: f775891af26b396c4f8a1563d3aff2b4d2cb66b2 172.38.0.16:6379
   replicates 8ed940e6e4b57e9913cbe83d6a86beb4068860c2
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: 9e2c4fbebec08cd915bec1ba631a3010e724a10e 172.38.0.11:6379
   slots:[0-5460] (5461 slots) master
   1 additional replica(s)
M: 8ed940e6e4b57e9913cbe83d6a86beb4068860c2 172.38.0.12:6379
   slots:[5461-10922] (5462 slots) master
   1 additional replica(s)
S: 0035700b84f47b4898537eae4fc2dd531eb9a0dd 172.38.0.15:6379
   slots: (0 slots) slave
   replicates 9e2c4fbebec08cd915bec1ba631a3010e724a10e
S: b6d34800dc58703e4efd2175cacdf3599ff5c8a6 172.38.0.14:6379
   slots: (0 slots) slave
   replicates a9f74adc02e988dbfd611ed3e76d0907487fcea6
M: a9f74adc02e988dbfd611ed3e76d0907487fcea6 172.38.0.13:6379
   slots:[10923-16383] (5461 slots) master
   1 additional replica(s)
S: f775891af26b396c4f8a1563d3aff2b4d2cb66b2 172.38.0.16:6379
   slots: (0 slots) slave
   replicates 8ed940e6e4b57e9913cbe83d6a86beb4068860c2
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

SpringBoot微服务打包Docker镜像

1、架构springboot项目

2、打包应用

3、编写dockerfile

4、构建镜像

5、发布运行!

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

到了这里我们已经完全够用了Docker!

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值