Docker入门

Docker简简单单入个门

  • 一、Docker概述
    • 1.Docker为什么出现
    • 2.Docker的历史
    • 3.Docker优点
    • 4.Docker实现DevOps(开发、运维)
    • 5.Docker的基本组成
  • 二、安装Docker
  • 三、运行流程及原理
    • 1.运行流程
    • 2.原理
  • 四、docker常用命令
    • 1.帮助命令
    • 2.镜像命令
      • docker images:查看镜像
      • docker search搜索镜像
      • docker pull下载镜像
      • docker rmi 删除镜像
    • 3.容器命令
      • 新建容器并启动
      • 列出所有运行容器
      • 退出容器
      • 删除容器
      • 启动和停止容器的操作
    • 4.其他命令
      • 后台启动命令
      • 查看日志
      • 查看容器中的进程信息
      • 查看镜像元数据
      • 进入当前正在运行的容器
      • 从容器内拷贝文件到主机上
  • 五、镜像
    • 1.UnionFs (联合文件系统)
    • 2.Docker镜像加载原理
    • 3.分层理解
    • 4.发布镜像
        • commit镜像
  • 六、容器数据卷
    • 1.概述
    • 2.具名和匿名挂载
    • 3.三种挂载方式
    • 4.拓展
    • 5.数据卷容器
  • 七、实战
    • 1.nginx
    • 2.tomcat
    • 3.mysql
    • 4.可视化界面
  • 八、DockerFile
    • 1.DockerFile介绍
    • 2.构建过程
    • 3.指令
    • 4.测试
    • 5.CMD和ENTRYPOINT的区别
    • 6.tomcat镜像实战
      • 1、准备镜像文件
      • 2、编写dokerfile
      • 3、构建镜像
      • 4、run镜像
      • 5、访问测试
      • 6、发布项目
    • 7.小结
  • 九、Docker网络
    • 1.理解网络原理
    • 2.--link(已经不建议使用
    • 3.自定义网络
    • 4.网络联通

博客链接:https://www.blog.23day.site/articles/60

一、Docker概述

1.Docker为什么出现

一款产品: 开发–上线中要有两套环境。会存在应用环境,应用配置等问题

由于版本更新等问题,导致服务不可用:对于运维来说考验很大

环境配置是十分的麻烦,每一个及其都要部署环境(集群Redis、ES、Hadoop…)

对于发布的一个项目来说 我们想可不可以直接带上环境打包(jar+Redis+Mysql等

  • 传统:开发jar,运维来做
  • 现在:开发打包部署上线,一套流程做完

安卓流程:java — apk —发布(应用商店)一 张三使用apk一安装即可用

docker流程: java-jar(环境) — 打包项目帯上环境(镜像) — ( Docker仓库:商店)

Docker思想来自于集装箱

隔离:Docker的核心思想。打包装箱,每个箱子都是相互隔离的,通过隔离机制,可以将服务器利用到极致

2.Docker的历史

2010年,几个的年轻人,就在美国成立了一家公司 dotcloud,做一些pass的云计算服务!LXC(Linux Container容器)有关的容器技术

Linux Container容器是一种内核虚拟化技术,可以提供轻量级的虚拟化,以便隔离进程和资源。

他们将自己的技术(容器化技术)命名就是 Docker。Docker刚刚延生的时候,没有引起行业的注意

2013年,Docker开源

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

2014年4月9日,Docker1.0发布

docker为什么这么火,十分的轻巧

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

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

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

虚拟机 Docker
linux centos原生镜像(一个电脑) 隔离镜像(最核心的环境 +jdk +mysql等)
需要开启多个虚拟机 运行镜像就可以了
几GB 几MB

3.Docker优点

优点:

  • 不模拟完整的操作系统,系统内核(kernel)非常小,更少的抽象层(GuestOS:如Centos)
  • 容器内的应用直接运行在宿主机的内核,容器本身没有自己的内核,也没有虚拟硬件。
  • 每个容器相互隔离,内部都有属于自己的文件系统,互不影响。

与传统虚拟机对比:

Docker入门_第1张图片

之前的虚拟机
Docker入门_第2张图片

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

容器化技术,不是一个完整的操作系统
Docker入门_第3张图片

容器内的应用直接运行在宿主机的内容,容器没有自己的内核,也没有虚拟我们的硬件

4.Docker实现DevOps(开发、运维)

  1. 应用快速的交付和部署

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

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

  2. 更便捷的升级和缩扩容

    使用Docker之后,部署应用就像搭积木一样,项目打包为一个镜像,扩展服务器A 服务器B

  3. 更简单的系统运维

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

  4. 更高效的计算资源应用

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

5.Docker的基本组成

Docker入门_第4张图片

  • 镜像(image):镜像是一种轻量级、可执行的独立软件包,用来打包软件运行环境和基于运行环境开发的软件。它包含运行某个软件所需的所有内容,包括代码、运行时、库、环境变量和配置文件。相当于一个模板,通过这个模板来创建容器服务,可以通过一个镜像创建多个容器。
  • 容器(container):独立运行一个或一组应用/基本命令有:启动,停止,删除等/可理解为一个简单的linux系统。
  • 仓库(repository):存放镜像的地方(公有/私有)Docker Hub是国外的,阿里云、华为云都有容器服务器(配置镜像加速)

二、安装Docker

官方推荐下载步骤

#1.卸载旧版本
yum remove docker \
                  docker-client \
                  docker-client-latest \
                  docker-common \
                  docker-latest \
                  docker-latest-logrotate \
                  docker-logrotate \
                  docker-engine
#2.需要的安装包
yum install -y yum-utils

#3.设置镜像的仓库
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
#上述方法默认是从国外的,不推荐

#推荐使用国内的
yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
    
#更新yum软件包索引
yum makecache

#4.安装docker相关的 docker-ce 社区版 而ee是企业版
yum install docker-ce docker-ce-cli containerd.io # 这里我们使用社区版即可

#5.启动docker
systemctl start docker

#6. 使用docker version查看是否按照成功
docker version

#7. 测试
docker run hello-world

第四步会出现两个问题,一个是需要提前下载一个包(或者修改一下官方给出的下载顺序

yum install https://download.docker.com/linux/fedora/30/x86_64/stable/Packages/containerd.io-1.2.6-3.3.fc30.x86_64.rpm

另一个是docker与podman冲突,需要卸载一下

yum erase podman buildah

删除docker步骤

#1. 卸载依赖
yum remove docker-ce docker-ce-cli containerd.io
#2. 删除资源
rm -rf /var/lib/docker
# /var/lib/docker 是docker的默认工作路径!

配置阿里云镜像加速

sudo mkdir -p /etc/docker

sudo tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": ["https://axvfsf7e.mirror.aliyuncs.com"]
}
EOF

sudo systemctl daemon-reload

sudo systemctl restart docker

三、运行流程及原理

1.运行流程

以hello-world为例
Docker入门_第5张图片

2.原理

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

Docker为什么比VM块?

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

Docker入门_第6张图片

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

四、docker常用命令

Docker入门_第7张图片

1.帮助命令

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

2.镜像命令

docker images:查看镜像

[root@iz2zeak7sgj6i7hrb2g862z ~]# docker images
REPOSITORY            TAG                 IMAGE ID            CREATED           SIZE
hello-world           latest              bf756fb1ae65        4 months ago     13.3kB
mysql                 5.7                 b84d68d0a7db        6 days ago       448MB

# 解释
#REPOSITORY			# 镜像的仓库源
#TAG				# 镜像的标签(版本)		---lastest 表示最新版本
#IMAGE ID			# 镜像的id
#CREATED			# 镜像的创建时间
#SIZE				# 镜像的大小

# 可选项
Options:
  -a, --all         Show all images (default hides intermediate images) #列出所有镜像
  -q, --quiet       Only show numeric IDs # 只显示镜像的id
  
[root@iz2zeak7sgj6i7hrb2g862z ~]# docker images -a  #列出所有镜像详细信息

[root@iz2zeak7sgj6i7hrb2g862z ~]# docker images -aq #列出所有镜像的id
d5f28a0bb0d0
f19c56ce92a8
1b6b1fe7261e
1b6b1fe7261e

docker search搜索镜像

[root@iz2zeak7sgj6i7hrb2g862z ~]# docker search mysql
# --filter=STARS=3000 #过滤,搜索出来的镜像收藏STARS数量大于3000的
Options:
  -f, --filter filter   Filter output based on conditions provided
      --format string   Pretty-print search using a Go template
      --limit int       Max number of search results (default 25)
      --no-trunc        Don't truncate output
      
[root@iz2zeak7sgj6i7hrb2g862z ~]# docker search mysql --filter=STARS=3000
NAME        DESCRIPTION         STARS            OFFICIAL        AUTOMATED
mysql       MySQL IS ...        9520             [OK]                
mariadb     MariaDB IS ...      3456             [OK]   

docker pull下载镜像

# 下载镜像 docker pull 镜像名[:tag]
[root@iz2zeak7sgj6i7hrb2g862z ~]# docker pull tomcat:8
8: Pulling from library/tomcat #如果不写tag,默认就是latest
90fe46dd8199: Already exists   #分层下载: docker image 的核心 联合文件系统
35a4f1977689: Already exists 
bbc37f14aded: Already exists 
74e27dc593d4: Already exists 
93a01fbfad7f: Already exists 
1478df405869: Pull complete 
64f0dd11682b: Pull complete 
68ff4e050d11: Pull complete 
f576086003cf: Pull complete 
3b72593ce10e: Pull complete 
Digest: sha256:0c6234e7ec9d10ab32c06423ab829b32e3183ba5bf2620ee66de866df # 签名防伪
Status: Downloaded newer image for tomcat:8
docker.io/library/tomcat:8 #真实地址

#等价于
docker pull tomcat:8
docker pull docker.io/library/tomcat:8

docker rmi 删除镜像

# docker rmi -f 镜像id     #删除指定id的镜像
docker rmi -f f19c56ce92a8

# docker rmi -f $(docker images -aq)    #删除全部的镜像
docker stop $(docker ps -a -q)

3.容器命令

新建容器并启动

docker run [options] 镜像名/id [command]  # 建立容器并启动:           
[options]:                  
         --name=容器名                # 命名容器以区分不同容器 tomcat01 tomcat02
         -d                          # 在后台运行容器(必须有一个前台进程,否则进程会自动关闭)
	    -it                          # 使用交互方式运行,进入容器查看内容
		-p					#指定容器的端口 -p 8080(宿主机):8080(容器)
				-p ip:主机端口:容器端口
				-p 主机端口:容器端口(常用)
				-p 容器端口
	    -P                           # 暴露容器所有端口
[command]:
            /bin/bash                    # 控制台

列出所有运行容器

docker ps 命令  		#列出当前正在运行的容器
  -a, --all     	 #列出当前正在运行的容器 + 带出历史运行过的容器
  -n=?, --last int   #列出最近创建的?个容器 ?为1则只列出最近创建的一个容器,为2则列出2个
  -q, --quiet        #只列出容器的编号

退出容器

exit 		#容器直接退出
ctrl +P +Q  #容器不停止退出 	---注意:这个很有用的操作

删除容器

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

4.其他命令

总结:

docker start/restart/stop/kill 容器名/id               
docker logs -tf --tail 显示的日志条数 容器名/id  # 查看日志
docker top 容器名/id                 # 查看容器中的进程信息
docker inspect 容器名/id             # 查看镜像的元数据
docker exec -it 容器名/id /bin/bash  # 通常容器以后台方式运行,需要进入其中修改配置:进入容器后开启一个新终端         
docker attach 容器名/id              # 进入容器正在执行的终端
docker cp 容器名/id:容器内路径 主机文件路径       # 从容器内拷贝文件到主机上

后台启动命令

# 命令 docker run -d 镜像名
[root@iz2zeak7sgj6i7hrb2g862z ~]# docker run -d centos
a8f922c255859622ac45ce3a535b7a0e8253329be4756ed6e32265d2dd2fac6c

[root@iz2zeak7sgj6i7hrb2g862z ~]# docker ps    
CONTAINER ID      IMAGE       COMMAND    CREATED     STATUS   PORTS    NAMES
# 问题docker ps. 发现centos 停止了
# 常见的坑,docker容器使用后台运行,就必须要有要一个前台进程,docker发现没有应用,就会自动停止
# nginx,容器启动后,发现自己没有提供服务,就会立刻停止,就是没有程序了

查看日志

docker logs --help
Options:
      --details        Show extra details provided to logs 

*  -f, --follow         Follow log output
   --since string   Show logs since timestamp (e.g. 2013-01-02T13:23:37) or relative (e.g. 42m for 42 minutes)
*  --tail string    Number of lines to show from the end of the logs (default "all")
*  -t, --timestamps     Show timestamps
   --until string   Show logs before a timestamp (e.g. 2013-01-02T13:23:37) or relative (e.g. 42m for 42 minutes)
   ➜  ~ docker run -d centos /bin/sh -c "while true;do echo 6666;sleep 1;done" #模拟日志      
   #显示日志
   -tf		#显示日志信息(一直更新)
   --tail number #需要显示日志条数
   docker logs -t --tail n 容器id #查看n行日志
   docker logs -ft 容器id #跟着日志

查看容器中的进程信息

# 命令 docker top 容器id
[root@localhost ~]# docker top 4f95779df41b
UID                 PID                 PPID                C                   STIME               TTY             
root                10225               10205               0                   18:30               ?            
root                10607               10225               0                   18:34               ?        

查看镜像元数据

docker inspect 4f95779df41b

进入当前正在运行的容器

# 我们通常容器都是在后台运行,需要进入容器,修改一些配置
# 方式一  docker exec -it 容器id bashshell
[root@localhost ~]# docker ps
CONTAINER ID   IMAGE     COMMAND                  CREATED          STATUS          PORTS     NAMES
4f95779df41b   centos    "/bin/sh -c 'while t…"   10 minutes ago   Up 10 minutes             nostalgic_edison
[root@localhost ~]# docker exec -it 4f95779df41b /bin/bash
[root@4f95779df41b /]# ls
bin  dev  etc  home  lib  lib64  lost+found  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var

# 方式二  dcoker attach 容器id
[root@localhost ~]# docker attach dce7bshk8oou7


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

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

docker cp 容器id:容器内路径  目的主机路径
# 查看当前主机目录下
[root@localhost home]# ls

[root@localhost home]# docker ps
CONTAINER ID   IMAGE     COMMAND       CREATED              STATUS              PORTS     NAMES
2ae552528a84   centos    "/bin/bash"   About a minute ago   Up About a minute             sleepy_kowalevski
# 进入docker容器内部
[root@localhost home]# docker exec -it 2ae552528a84 /bin/bash
[root@2ae552528a84 /]# cd /home
[root@2ae552528a84 home]# ls
# 在容器内部进行创建文件
[root@2ae552528a84 home]# touch test.java
[root@2ae552528a84 home]# exit
exit
[root@localhost home]# docker ps -a
CONTAINER ID   IMAGE     COMMAND       CREATED         STATUS                     PORTS     NAMES
2ae552528a84   centos    "/bin/bash"   3 minutes ago   Exited (0) 6 seconds ago             sleepy_kowalevski
# 见文件拷贝出来到主机上
[root@localhost home]# docker cp 2ae552528a84:/home/test.java /home
[root@localhost home]# ls
test.java
# 拷贝是一个手动过程,未来我们可以使用-v卷的技术,可以实现自动同步 /home /home

五、镜像

1.UnionFs (联合文件系统)

  • UnionFs(联合文件系统):Union文件系统(UnionFs)是一种分层、轻量级并且高性能的文件系统,他支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下。Union文件系统是 Docker镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像
  • 特性:一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录。

2.Docker镜像加载原理

Docker入门_第8张图片

Docker的镜像实际由一层一层的文件系统组成:

  • bootfs(boot file system)主要包含bootloader和kernel。bootloader主要是引导加载kernel,完成后整个内核就都在内存中了。此时内存的使用权已由bootfs转交给内核,系统卸载bootfs。可以被不同的Linux发行版公用。
  • rootfs(root file system),包含典型Linux系统中的/dev,/proc,/bin,/etc等标准目录和文件。rootfs就是各种不同操作系统发行版(Ubuntu,Centos等)。因为底层直接用Host的kernel,rootfs只包含最基本的命令,工具和程序就可以了。

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

3.分层理解

所有的Docker镜像都起始于一个基础镜像层,当进行修改或增加新的内容时,就会在当前镜像层之上,创建新的容器层。
容器在启动时会在镜像最外层上建立一层可读写的容器层(R/W),而镜像层是只读的(R/O)。
Docker入门_第9张图片

[root@localhost ~]# docker image inspect redis:latest
"RootFS": {
            "Type": "layers",
            "Layers": [
                "sha256:7e718b9c0c8c2e6420fe9c4d1d551088e314fe923dce4b2caf75891d82fb227d",
                "sha256:89ce1a07a7e4574d724ea605b4877f8a73542cf6abd3c8cbbd2668d911fa5353",
                "sha256:9eef6e3cc2937e452b2325b227ca28120a70481be25404ed9aad27fa81219fd0",
                "sha256:ee748697d275b904f1d5604345d70b647a8c145b9f05aeb5ca667e1f256e43d8",
                "sha256:f1f7964d40afa49c6ef63ab11af91044e518a2539f567783ce997d3cea9ce8f6",
                "sha256:3d9fda8ff875e549d54e9d7504ce17d27423fe27dafbb92127c603dddad7fa13"
            ]
        },

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

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

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

在添加额外的镜像层的同时,镜像始终保持是当前所有镜像的组合,理解这一点.
Docker入门_第10张图片

在添加额外的镜像层的同时,镜像始终保持是当前所有镜像的组合,理解这一点非常重要。下图中举了一个简单的例子,每个镜像层包含3个文件,而镜像包含了来自两个镜像层的6个文件。
Docker入门_第11张图片

上图中的镜像层跟之前图中的略有区別,主要目的是便于展示文件
下图中展示了一个稍微复杂的三层镜像,在外部看来整个镜像只有6个文件,这是因为最上层中的文件7是文件5的一个更新版。
Docker入门_第12张图片

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

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

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

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

下图展示了与系统显示相同的三层镜像。所有镜像层堆并合井,对外提供统一的视图。
Docker入门_第13张图片

Docker镜像都是只读的,当容器启动时,一个新的可写层被加载到镜像顶部。这一层就是我们通常说的容器层,容器之下的都叫镜像层
Docker入门_第14张图片

4.发布镜像

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

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

六、容器数据卷

1.概述

为了实现数据持久化,使容器之间可以共享数据。可以将容器内的目录,挂载到宿主机上或其他容器内,实现同步和共享的操作。即使将容器删除,挂载到本地的数据卷也不会丢失。

容器的持久化和同步操作,容器间也是可以数据共享的
Docker入门_第15张图片

2.具名和匿名挂载

# 匿名挂载
-v 容器内路径!
$ docker run -d -P --name nginx01 -v /etc/nginx nginx

# 查看所有的volume(卷)的情况
$ docker volume ls    
DRIVER              VOLUME NAME # 容器内的卷名(匿名卷挂载)
local               21159a8518abd468728cdbe8594a75b204a10c26be6c36090cde1ee88965f0d0
local               b17f52d38f528893dd5720899f555caf22b31bf50b0680e7c6d5431dbda2802c
         
# 这里发现,这种就是匿名挂载,我们在 -v只写了容器内的路径,没有写容器外的路径

# 具名挂载 -P:表示随机映射端口
$ docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx nginx
9663cfcb1e5a9a1548867481bfddab9fd7824a6dc4c778bf438a040fe891f0ee

# 查看所有的volume(卷)的情况
$ docker volume ls                  
DRIVER              VOLUME NAME
local               21159a8518abd468728cdbe8594a75b204a10c26be6c36090cde1ee88965f0d0
local               b17f52d38f528893dd5720899f555caf22b31bf50b0680e7c6d5431dbda2802c
local               juming-nginx #多了一个名字


# 通过 -v 卷名:查看容器内路径
# 查看一下这个卷
$ docker volume inspect juming-nginx
[
    {
        "CreatedAt": "2020-05-23T13:55:34+08:00",
        "Driver": "local",
        "Labels": null,
        "Mountpoint": "/var/lib/docker/volumes/juming-nginx/_data", #默认目录
        "Name": "juming-nginx",
        "Options": null,
        "Scope": "local"
    }
]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-l12KaM1J-1644282103817)(img/Docker/image-20220207153554831.png)]

3.三种挂载方式

所有docker容器内的卷,在未指定主机内目录时,都在:/var/lib/docker/volumes/卷名/_data 下,可通过具名挂载可以方便的找到卷,因此广泛使用这种方式进行挂载。

# 三种挂载: 匿名挂载、具名挂载、指定路径挂载
-v 容器内路径			#匿名挂载
-v 卷名:容器内路径		  #具名挂载
-v /宿主机路径:容器内路径 #指定路径挂载 docker volume ls 是查看不到的

4.拓展

# 通过 -v 容器内路径: ro rw 改变读写权限
ro #readonly 只读
rw #readwrite 可读可写
$ docker run -d -P --name nginx05 -v juming:/etc/nginx:ro nginx
$ docker run -d -P --name nginx05 -v juming:/etc/nginx:rw nginx

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

5.数据卷容器

重点:三个容器的共享卷均挂载到宿主机的某物理地址,而不是三个容器间实现的互相拷贝或者引用

# 测试 启动3个容器
# 创建docker01
$ docker run -it --name docker01 centos

# 查看容器docekr01内容
$ ls
bin  home   lost+found	opt   run   sys  var
dev  lib    media	proc  sbin  tmp  volume01
etc  lib64  mnt		root  srv   usr  volume02

# 不关闭该容器退出
CTRL + Q + P  

# 创建docker02: 并且让docker02 继承 docker01
$ docker run -it --name docker02 --volumes-from docker01 centos

# 查看容器docker02内容
$ ls
bin  home   lost+found	opt   run   sys  var
dev  lib    media	proc  sbin  tmp  volume01
etc  lib64  mnt		root  srv   usr  volume02

# 再新建一个docker03同样继承docker01
$ docker run -it --name docker03 --volumes-from docker01 centos
$ cd volume01	#进入volume01 查看是否也同步docker01的数据
$ ls 
docker01.txt

# 测试:可以删除docker01,查看一下docker02和docker03是否可以访问这个文件
# 测试发现:数据依旧保留在docker02和docker03中没有被删除

七、实战

1.nginx

# 1、搜索镜像
[root@localhost home]# docker search nginx

# 2、拉取镜像
[root@localhost home]# docker pull nginx

# 3、查看镜像
[root@localhost home]# docker images
REPOSITORY   TAG       IMAGE ID       CREATED        SIZE
nginx        latest    62d49f9bab67   3 weeks ago    133MB
centos       latest    300e315adb2f   4 months ago   209MB

# 4、启动运行
[root@localhost home]# docker run -d --name nginx01 -p 3344:80 nginx
66f84ea1a1679cc5f062e4c7aab26f051d30df710e23e7685597257933eb7d61

# 5、查看运行情况
[root@localhost home]# docker ps
CONTAINER ID   IMAGE     COMMAND                  CREATED          STATUS          PORTS                                   NAMES
66f84ea1a167   nginx     "/docker-entrypoint.…"   31 seconds ago   Up 29 seconds   0.0.0.0:3344->80/tcp, :::3344->80/tcp   nginx01

# 6、本机自测运行情况
[root@localhost home]# curl localhost:3344

# 7、进入容器,修改配置
[root@localhost home]# docker exec -it nginx01 /bin/bash
root@66f84ea1a167:/# whereis nginx
nginx: /usr/sbin/nginx /usr/lib/nginx /etc/nginx /usr/share/nginx
root@66f84ea1a167:/# cd /etc/nginx

2.tomcat

# 之前的启动都是后台,停止了容器,容器还是可以查到, docker run -it --rm 镜像名 一般是用来测试,用完就删除容器
[root@iz2zeak7sgj6i7hrb2g862z ~]# docker run -it --rm tomcat:9.0

--rm       Automatically remove the container when it exits 用完即删

#下载
[root@iz2zeak7sgj6i7hrb2g862z ~]# docker pull tomcat

#查看下载的镜像
[root@iz2zeak7sgj6i7hrb2g862z ~]# docker images

#以后台方式,暴露端口方式,启动运行
[root@iz2zeak7sgj6i7hrb2g862z ~]# docker run -d -p 8080:8080 --name tomcat01 tomcat

#测试访问有没有问题
curl localhost:8080

#根据容器id进入tomcat容器
[root@iz2zeak7sgj6i7hrb2g862z ~]# docker exec -it 645596565d3f /bin/bash
root@645596565d3f:/usr/local/tomcat# 
#查看tomcat容器内部内容:
root@645596565d3f:/usr/local/tomcat# ls -l
total 152
-rw-r--r-- 1 root root 18982 May  5 20:40 BUILDING.txt
-rw-r--r-- 1 root root  5409 May  5 20:40 CONTRIBUTING.md
-rw-r--r-- 1 root root 57092 May  5 20:40 LICENSE
-rw-r--r-- 1 root root  2333 May  5 20:40 NOTICE
-rw-r--r-- 1 root root  3255 May  5 20:40 README.md
-rw-r--r-- 1 root root  6898 May  5 20:40 RELEASE-NOTES
-rw-r--r-- 1 root root 16262 May  5 20:40 RUNNING.txt
drwxr-xr-x 2 root root  4096 May 16 12:05 bin
drwxr-xr-x 1 root root  4096 May 21 11:04 conf
drwxr-xr-x 2 root root  4096 May 16 12:05 lib
drwxrwxrwx 1 root root  4096 May 21 11:04 logs
drwxr-xr-x 2 root root  4096 May 16 12:05 native-jni-lib
drwxrwxrwx 2 root root  4096 May 16 12:05 temp
drwxr-xr-x 2 root root  4096 May 16 12:05 webapps
drwxr-xr-x 7 root root  4096 May  5 20:37 webapps.dist
drwxrwxrwx 2 root root  4096 May  5 20:36 work
root@645596565d3f:/usr/local/tomcat# 
#进入webapps目录
root@645596565d3f:/usr/local/tomcat# cd webapps
root@645596565d3f:/usr/local/tomcat/webapps# ls
root@645596565d3f:/usr/local/tomcat/webapps# 
# 发现问题:1、linux命令少了。 2.webapps目录为空 
# 原因:阿里云镜像的原因,阿里云默认是最小的镜像,所以不必要的都剔除掉
# 保证最小可运行的环境!
# 解决方案:
# 将webapps.dist下的文件都拷贝到webapps下即可
root@645596565d3f:/usr/local/tomcat# ls 
# 找到webapps.dist
BUILDING.txt	 LICENSE  README.md	 RUNNING.txt  conf  logs  temp     webapps.dist
CONTRIBUTING.md  NOTICE   RELEASE-NOTES  bin   lib   native-jni-lib  webapps  work

root@645596565d3f:/usr/local/tomcat# cd webapps.dist/ 
# 进入webapps.dist 
root@645596565d3f:/usr/local/tomcat/webapps.dist# ls 
ROOT  docs  examples  host-manager  manager

root@645596565d3f:/usr/local/tomcat/webapps.dist# cd ..
root@645596565d3f:/usr/local/tomcat# cp -r webapps.dist/* webapps 
# 拷贝webapps.dist 内容给webapps
root@645596565d3f:/usr/local/tomcat# cd webapps 
#进入webapps
root@645596565d3f:/usr/local/tomcat/webapps# ls 
#查看拷贝结果
ROOT  docs  examples  host-manager  manager

3.mysql

# 获取mysql镜像
[root@iz2zeak7sgj6i7hrb2g862z home]# docker pull mysql

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

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

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

# 启动成功之后,我们在本地使用workbench来测试一下
# workbench-连接到服务器的3306--和容器内的3306映射 

# 在本地测试创建一个数据库,查看一下我们映射的路径是否ok!

4.可视化界面

portainer

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

八、DockerFile

1.DockerFile介绍

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

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

步骤:

  1. 编写一个dockerfile文件

  2. docker build 构建称为一个镜像

  3. docker run运行镜像

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

2.构建过程

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4PPqwKJY-1644282103818)(img/Docker/411dbfc840cd72f6a493af6daff574d0.png)]

3.指令

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

Docker入门_第16张图片

4.测试

# 1./home下新建dockerfile目录
$ mkdir dockerfile

# 2. dockerfile目录下新建mydockerfile文件
$ vim mydockerfile

# 3.编写Dockerfile配置文件
FROM centos							# 基础镜像是官方原生的centos
MAINTAINER username<123465@qq.com>  	# 作者

ENV MYPATH /usr/local				# 配置环境变量的目录 
WORKDIR $MYPATH						# 将工作目录设置为 MYPATH

RUN yum -y install vim				# 给官方原生的centos 增加 vim指令
RUN yum -y install net-tools		# 给官方原生的centos 增加 ifconfig命令 
# 在最新的centos8中因为没有配置源 所以这个命令无法执行

EXPOSE 80							# 暴露端口号为80

CMD echo $MYPATH					# 输出下 MYPATH 路径
CMD echo "-----end----"				
CMD /bin/bash						# 启动后进入 /bin/bash

# 4.通过这个文件构建镜像
# 命令: docker build -f 文件路径 -t 镜像名:[tag] .
$ docker build -f mydockerfile -t mycentos:0.1 .

# 5.查看镜像
$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
mycentos            0.1                 cbf5110a646d        2 minutes ago       311MB

# 6.测试运行
$ docker run -it mycentos:0.1 		# 注意带上版本号,否则每次都回去找最新版latest
$ pwd	
/usr/local							# 与Dockerfile文件中 WORKDIR 设置的 MYPATH 一致
$ vim								# vim 指令可以使用
$ ifconfig     						# ifconfig 指令可以使用

# 7.docker history 镜像id 查看镜像构建历史步骤
$ docker history 镜像id

5.CMD和ENTRYPOINT的区别

CMD:

# 编写dockerfile文件
$ vim dockerfile-test-cmd
FROM centos
CMD ["ls","-a"]					# 启动后执行 ls -a 命令

# 构建镜像
$ docker build  -f dockerfile-test-cmd -t cmd-test:0.1 .

# 运行镜像
$ docker run cmd-test:0.1		# 由结果可得,运行后就执行了 ls -a 命令
.
..
.dockerenv
bin
dev
etc
home

# 想追加一个命令  -l 成为ls -al:展示列表详细数据
$ docker run cmd-test:0.1 -l
docker: Error response from daemon: OCI runtime create failed: container_linux.go:349: starting container process caused "exec: \"-l\":
executable file not found in $PATH": unknown.
ERRO[0000] error waiting for container: context canceled 

# cmd的情况下 -l 替换了CMD["ls","-l"] 而 -l  不是命令所以报错

ENTRYPOINT:

# 编写dockerfile文件
$ vim dockerfile-test-entrypoint
FROM centos
ENTRYPOINT ["ls","-a"]

# 构建镜像
$ docker build  -f dockerfile-test-entrypoint -t cmd-test:0.1 .

# 运行镜像
$ docker run entrypoint-test:0.1
.
..
.dockerenv
bin
dev
etc

# 我们的命令,是直接拼接在我们得ENTRYPOINT命令后面的
$ docker run entrypoint-test:0.1 -l
total 56
drwxr-xr-x   1 root root 4096 May 16 06:32 .
drwxr-xr-x   1 root root 4096 May 16 06:32 ..
-rwxr-xr-x   1 root root    0 May 16 06:32 .dockerenv
lrwxrwxrwx   1 root root    7 May 11  2019 bin -> usr/bin
drwxr-xr-x   5 root root  340 May 16 06:32 dev

6.tomcat镜像实战

1、准备镜像文件

准备tomcat 和 jdk 到当前目录,编写好README

2、编写dokerfile

FROM centos 										# 基础镜像centos
MAINTAINER cao<1165680007@qq.com>					# 作者
COPY README /usr/local/README 						# 复制README文件
ADD jdk-8u231-linux-x64.tar.gz /usr/local/ 			# 添加jdk,ADD 命令会自动解压
ADD apache-tomcat-9.0.35.tar.gz /usr/local/ 		# 添加tomcat,ADD 命令会自动解压
RUN yum -y install vim								# 安装 vim 命令
ENV MYPATH /usr/local 								# 环境变量设置 工作目录
WORKDIR $MYPATH

ENV JAVA_HOME /usr/local/jdk1.8.0_231 				# 环境变量: JAVA_HOME环境变量
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar

ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.35 	# 环境变量: tomcat环境变量
ENV CATALINA_BASH /usr/local/apache-tomcat-9.0.35

# 设置环境变量 分隔符是:
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin 	

EXPOSE 8080 										# 设置暴露的端口

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

3、构建镜像

docker build -t mytomcat:0.1 .

4、run镜像

# -d:后台运行 -p:暴露端口 --name:别名 -v:绑定路径 
$ docker run -d -p 8080:8080 --name tomcat01 
-v /home/kuangshen/build/tomcat/test:/usr/local/apache-tomcat-9.0.35/webapps/test 
-v /home/kuangshen/build/tomcat/tomcatlogs/:/usr/local/apache-tomcat-9.0.35/logs mytomcat:0.1

5、访问测试

$ docker exec -it 自定义容器的id /bin/bash

$ cul localhost:8080

6、发布项目

7.小结

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yDefQuR0-1644282103819)(img/Docker/cab627703fe9866a82d682e5951da112.png)]

九、Docker网络

1.理解网络原理

Docker入门_第17张图片

[root@localhost ~]# docker run -d -P --name tomcat01 tomcat

# 查看容器的内部网络地址 ip addr,发现容器启动的是否会得到一个eth0@if85 ip地址,docker分配
[root@localhost ~]# docker exec -it tomcat01 ip addr
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
84: eth0@if85: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
       valid_lft forever preferred_lft forever

# 思考Linux能不能ping通容器内部
[root@localhost ~]# ping 172.17.0.2
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.395 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.149 ms

# Linux可以ping通docker容器内部

原理

Docker入门_第18张图片

我们发现这些网卡都是一对对的

veth-pair 就是一对的虚拟设备接口,它们都是成对出现的,一段连着协议,一段彼此相连

我们每启动一个docker容器,docker就会给容器分配一个默认的可用ip,我们只要安装了docker,就会有一个网卡docker0(bridge)。网卡采用桥接模式,并使用veth-pair技术(veth-pair就是一堆虚拟设备接口,成对出现,一段连着协议,一段彼此相连,充当一个桥梁。)。

3、我们来测试下tomcat01和tomcat02是否可以ping通

# 获取tomcat01的ip 172.17.0.2
$ docker-tomcat docker exec -it tomcat01 ip addr  
550: eth0@if551: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
       valid_lft forever preferred_lft forever
      

# 让tomcat02 ping tomcat01       
$ docker-tomcat docker exec -it tomcat02 ping 172.17.0.2
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.098 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.071 ms

结论:

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

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

Docker入门_第19张图片

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

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

只要容器删除,对应的网桥就没了
Docker入门_第20张图片

2.–link(已经不建议使用

$ docker exec -it tomcat02 ping tomca01   # ping不通
ping: tomca01: Name or service not known

# 运行一个tomcat03 --link tomcat02 
$ docker run -d -P --name tomcat03 --link tomcat02 tomcat
5f9331566980a9e92bc54681caaac14e9fc993f14ad13d98534026c08c0a9aef

# 3连接2
# 用tomcat03 ping tomcat02 可以ping通
$ docker exec -it tomcat03 ping tomcat02
PING tomcat02 (172.17.0.3) 56(84) bytes of data.
64 bytes from tomcat02 (172.17.0.3): icmp_seq=1 ttl=64 time=0.115 ms
64 bytes from tomcat02 (172.17.0.3): icmp_seq=2 ttl=64 time=0.080 ms

# 2连接3
# 用tomcat02 ping tomcat03 ping不通

–link 本质就是在hosts配置中添加映射

Docker入门_第21张图片

现在使用Docker已经不建议使用–link了!

3.自定义网络

docker network
connect     -- Connect a container to a network
create      -- Creates a new network with a name specified by the
disconnect  -- Disconnects a container from a network
inspect     -- Displays detailed information on a network
ls          -- Lists all the networks created by the user
prune       -- Remove all unused networks
rm          -- Deletes one or more networks

Docker入门_第22张图片

网络模式

  • bridge :桥接 docker(默认,自己创建也是用bridge模式)

  • none :不配置网络,一般不用

  • host :和所主机共享网络

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

测试

# 我们直接启动的命令 默认参数:--net bridge,而这个就是我们得docker0

# bridge就是docker0
$ docker run -d -P --name tomcat01 tomcat
等价于 => docker run -d -P --name tomcat01 --net bridge tomcat

# docker0,特点:默认,域名不能访问。 --link可以打通连接,但是很麻烦!

# 我么可以自定义一个网络
# --driver bridge
# --subnet 192.168.0.0/16 192.168.0.2 192.168.255.255
# --gateway 192.168.0.1
[root@localhost ~]# docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
7637416b83c39b59e8af8e5b79f95f55b2cf3700017a547c3b5f2596fa637fd2

[root@localhost ~]# docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
e57926bed59d   bridge    bridge    local
b97cfa843b69   host      host      local
7637416b83c3   mynet     bridge    local
12a56a664499   none      null      local

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QXPYXxo3-1644282103824)(img/Docker/abe7609e2eaff96767fb63e00e15ab74.png)]

[root@localhost ~]# docker run -d -P --name tomcat-net-01 --net mynet tomcat
959374947ce0f666073cd160b0ed3f727c72f24f907754c62d377d66d48b885d
[root@localhost ~]# docker run -d -P --name tomcat-net-02 --net mynet tomcat
7b6b415d88222daf44c8542121cd7256e398fb4dd2880c74a8d4db0077245a8b
[root@localhost ~]# docker network inspect mynet
    {
        "Name": "mynet",
        "Id": "7637416b83c39b59e8af8e5b79f95f55b2cf3700017a547c3b5f2596fa637fd2",
        "Driver": "bridge",
        "IPAM": {
            "Config": [
                {
                    "Subnet": "192.168.0.0/16",
                    "Gateway": "192.168.0.1"
                }
            ]

        "Containers": {
            "7b6b415d88222daf44c8542121cd7256e398fb4dd2880c74a8d4db0077245a8b": {
                "Name": "tomcat-net-02",
                "EndpointID": "9c8a2979e3c1b9914fde4502298ec3aa35bd004a178d695222629fc613f482df",
                "MacAddress": "02:42:c0:a8:00:03",
                "IPv4Address": "192.168.0.3/16",
                "IPv6Address": ""
            },
            "959374947ce0f666073cd160b0ed3f727c72f24f907754c62d377d66d48b885d": {
                "Name": "tomcat-net-01",
                "EndpointID": "b98aee7d07ecaea623dad5318076b32dd67bbb7a4eafa35e6d1e9605ab71f661",
                "MacAddress": "02:42:c0:a8:00:02",
                "IPv4Address": "192.168.0.2/16",
                "IPv6Address": ""
            }
# 再次测试ping连接
[root@localhost ~]# docker exec -it tomcat-net-01 ping 192.168.0.3
PING 192.168.0.3 (192.168.0.3) 56(84) bytes of data.
64 bytes from 192.168.0.3: icmp_seq=1 ttl=64 time=0.177 ms
64 bytes from 192.168.0.3: icmp_seq=5 ttl=64 time=0.135 ms

# 现在不需要使用--link也可以ping名字了!
[root@localhost ~]# docker exec -it tomcat-net-01 ping tomcat-net-02
PING tomcat-net-02 (192.168.0.3) 56(84) bytes of data.
64 bytes from tomcat-net-02.mynet (192.168.0.3): icmp_seq=1 ttl=64 time=0.087 ms
64 bytes from tomcat-net-02.mynet (192.168.0.3): icmp_seq=4 ttl=64 time=0.103 ms

4.网络联通

Docker入门_第23张图片

对于建立在不同网络下(docker0, newnet)的两个容器tomcat01和tomcat02,他们的网段不同,因此是无法彼此ping通容器内部的

Docker入门_第24张图片

这时我们需要通过docker network connect命令打通容器与网络之间的连接

Docker入门_第25张图片

# 测试打通 tomcat01 - mynet
[root@localhost ~]# docker network connect mynet tomcat01

# 连通之后将tomcat01放到了mynet网络下

# 一个容器两个ip地址 阿里云服务:公网ip 私网ip

Docker入门_第26张图片

你可能感兴趣的:(运维,docker,容器,运维)