学习笔记:云原生容器化技术——Docker

Docker学习笔记

  • 前言
  • 一、Docker概述
    • 1.1 Docker为什么会出现?
    • 1.2 Docker的历史
    • 1.3 Docker为什么这么火爆?
    • 1.4 虚拟机技术与容器化技术的区别
  • 二、Docker安装
    • 2.1 Docker的基本组成
    • 2.2 Docker安装
    • 2.3 阿里云镜像加速
    • 2.4 docker run的执行流程
    • 2.5 Docker工作原理
  • 三、Docker命令
    • 3.1 镜像命令
    • 3.2 容器命令
    • 3.3 其他常用命令
    • 3.4 小结
    • 3.5 练习使用Docker部署Nginx
    • 3.5 可视化工具
  • 四、Docker镜像
    • 4.1 镜像是什么
    • 4.2 Docker镜像加载原理
    • 4.3 分层的理解
    • 4.4 commit镜像
  • 五、容器数据卷
    • 5.1 什么是容器数据卷
    • 5.2 容器数据卷使用方式一:参数-v
    • 5.3 具名挂载与匿名挂载
    • 5.4 容器数据卷使用方式二:Dockerfile
    • 5.5 数据卷容器
  • 六、DockerFile
    • 6.1 DockerFile介绍
    • 6.2 DockerFile构建过程
    • 6.3 DockerFile命令
    • 6.4 实战测试
    • 6.4 CMD与ENTRYPOINT的区别
    • 6.5 实战:制作Tomcat镜像
    • 6.6 发布自己的镜像
  • Docker命令小结
  • 七、Docker网络原理
    • 7.1 理解docker0
  • 八、IDEA整合Docker
  • 九、Docker Compose
  • 十、Docker Swarm
  • 十一、CI\CD Jenkins


前言

弱小和无知并非生存的障碍,傲慢才是。生活要常以谦卑的心态

一、Docker概述

1.1 Docker为什么会出现?

首先,我们进行软件研发需要开发dev、线上prod两套环境,容易存在问题:

  1. 版本更新导致服务不可用
  2. 环境部署较麻烦(尤其是集群Redis、ES、Hadoop)

比如发布一个jar项目,但该jar的运行需要依赖Redis、ES、Hadoop等环境,也就是说部署该项目需要先安装以上几种环境,此时部署该项目就比较费时费力。如果能把这个项目与环境打包在一起部署,就会效率很多。

Docker给以上问题提供了解决方案,具体应用类似于打包Java程序为apk文件发布到应用商店,下次使用的时候在应用商店下载即可:

  • Java程序 —— .apk —— 发布到应用商店 ------ 用户下载该.apk安装使用
  • Java程序 —— 打包项目与环境为镜像(jar+依赖环境) —— 上传到Docker仓库 ------ 运维下载发布的镜像直接运行

其思想来自于集装箱,将项目与环境打包装箱,每个箱子是互相隔离的,Docker通过隔离机制,可以将服务器资源利用到极致。

1.2 Docker的历史

2010年,几个程序员在美国成立了一家名为dotCloud的公司,其旨在提供pass云计算服务(LXC有关的容器技术)。他们将自己的技术(容器化技术)命名为Docker,然而Docker刚刚诞生时并没有引起行业的关注。
2013年,dotCloud公司效益越发不景气,所以他们选择开源Docker技术。后来越来越多的人发现了Docker的优点,Docker火了,往后的每个月Docker都会更新一个新的版本。
2014年4月9日,Docker 1.0发布。

1.3 Docker为什么这么火爆?

简言:十分轻巧。在容器技术现世之前,我们使用的是虚拟机技术(VM),在windows中安装一个Vmware,通过这个软件我们可以虚拟出来一台或多台电脑,比较笨重。虚拟机属于虚拟化技术,Docker容器技术也属于虚拟化技术。

  • VM,Linux Centos原生镜像(即一台电脑)隔离,需要开启多个虚拟机,占用几个G存储空间,耗时几分钟
  • Docker,镜像机制(最核心的环境:JDK+MySQL+Redis,十分轻巧)隔离,直接运行即可,仅占用几十M存储空间,耗时为秒级别
    学习笔记:云原生容器化技术——Docker_第1张图片

Docker是基于Go语言开发的开源项目
官网地址:https://www.docker.com/
文档地址:https://docs.docker.com/
仓库地址:https://hub.docker.com/

1.4 虚拟机技术与容器化技术的区别

  • 虚拟机技术:传统虚拟机虚拟出一个硬件,运行一个完整的操作系统,然后在这个系统上安装、运行软件。缺点:资源占用多、冗余步骤多、启动缓慢
    学习笔记:云原生容器化技术——Docker_第2张图片
  • 容器化技术:并非模拟一个完整的操作系统,下图中的每一个小方块代表一个镜像。容器内的应用直接运行中在宿主机中,容器没有自己的内核,也没有虚拟硬件,所以很轻便。每个容器相互隔离,每个容器都有一个属于自己的文件系统,互不影响。
    学习笔记:云原生容器化技术——Docker_第3张图片

在DevOps(开发、运维)方面

  • 更快的交付和部署
    传统的部署:一堆帮助文档、安装程序
    Docker部署:一键运行打包镜像、发布测试
  • 更便捷的升级和扩缩容
    Docker部署应用像搭积木一样。比如一个项目使用了SpringBoot 1.5、Redis 5、Tomcat 8三种环境,其中Tomcat需要进行版本升级,Docker将其打包成镜像,现只需要升级该镜像并测试,后续的部署只需使用该镜像就可以了。服务器性能到瓶颈要水平扩展也更便捷
  • 更简单的系统运维
    在容器化后,测试环境和线上环境高度一致
  • 更高效的计算资源利用
    Docker是内核级别的虚拟化,可以在一个物理机上运行很多容器实例。服务器的性能可以发挥到极致

二、Docker安装

2.1 Docker的基本组成

学习笔记:云原生容器化技术——Docker_第4张图片
镜像(image):Docker镜像就好比是一个模板,可以通过这个模板来创建容器服务,tomcat镜像 ==> run ==> tomcat01容器(提供服务)
容器(contianer):Docker利用容器技术独立运行一个或一组应用,容器是通过镜像来创建的。容器可以启动、停止、删除,都可以使用命令进行操作。目前可以把一个容器理解为是一个简易的Linux系统
仓库(repository):Docker仓库用来存放镜像,仓库分为公有仓库和私有仓库。DockerHub(默认是国外的)、阿里云等都有容器服务器(配置镜像加速)

2.2 Docker安装

环境准备

[root@ziang ~]# uname -r 				# 查看系统内核版本
3.10.0-1127.19.1.el7.x86_64
[root@ziang ~]# 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. 卸载旧版本
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 
				http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo # 使用国内阿里云镜像仓库
# 更新yum软件包索引
yum makecache fast
# 4. 安装Docker引擎:docker引擎、docker客户端、守护进程containerd
yum install docker-ce docker-ce-cli containerd.io
# 5. 启动Docker
systemctl start docker
# 6. 查看Docker版本信息
docker version
# 7. Helloworld
docker run hello-world
# 8. 查看下载的hello-world镜像
docker images
# 9. (另)卸载Docker
yum remove docker-ce docker-ce-cli containerd.io
rm -rf /var/lib/docker

Docker的默认工作路径(工作目录):/var/lib/docker

2.3 阿里云镜像加速

  1. 登录阿里云找到镜像容器
  2. 找到镜像加速
  3. 配置使用
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": ["https://f9ognzpb.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker

2.4 docker run的执行流程

学习笔记:云原生容器化技术——Docker_第5张图片

2.5 Docker工作原理

Docker是一个Client-Server架构的系统,Docker的守护进程运行在主机上,通过socket从客户端访问,docker-server接受到docker-client的指令就会执行
学习笔记:云原生容器化技术——Docker_第6张图片
Docker为什么比VM快?

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

学习笔记:云原生容器化技术——Docker_第7张图片

由图可见,新建容器时Docker无需像虚拟机那样重新加载一个操作系统内核。虚拟机加载Guest OS耗时在分钟级别,而Docker利用宿主机省略了这个过程,耗时是秒级
学习笔记:云原生容器化技术——Docker_第8张图片


三、Docker命令

帮助命令

docker version		docker版本信息
docker info			docker配置信息,包括镜像和容器数量
docker 命令 --help	docker帮助命令,万能

官方帮助文档地址:https://docs.docker.com/engine/reference/run/

3.1 镜像命令

查看本地所有镜像:docker images

[root@ziang /]# docker images
REPOSITORY    TAG          IMAGE ID       CREATED        SIZE
hello-world   latest       feb5d9fea6a5   4 months ago   13.3kB
rabbitmq      management   246db2517862   8 months ago   186MB
# 列名解释
REPOSITORY  	 镜像的仓库源
TAG				 镜像的标签
IMAGE ID	     镜像的ID
CREATE			 镜像的创建时间
SIZE			 镜像的大小

# 可选项
--all , -a		 Show all images (default hides intermediate images)
--quiet , -q	Only show image IDs

在镜像仓库中搜索镜像:docker search

[root@ziang ~]# docker search mysql
NAME                              DESCRIPTION                                     STARS     OFFICIAL   AUTOMATED
mysql                             MySQL is a widely used, open-source relation…   12047     [OK]       
mariadb                           MariaDB Server is a high performing open sou…   4618      [OK]       
mysql/mysql-server                Optimized MySQL Server Docker images. Create…   901                  [OK]
# 可选项:通过搜索过滤
--filter=STARS=3000		# 搜索出来STARS大于3000的命令

在镜像仓库中下载镜像:docker pull

[root@ziang ~]# docker pull mysql
Using default tag: latest				# 如果不指定tag,默认latest
latest: Pulling from library/mysql
72a69066d2fe: Pull complete 			# 分层下载,docker image的核心,联合文件系统
93619dbc5b36: Pull complete 
99da31dd6142: Pull complete 
626033c43d70: Pull complete 
37d5d7efb64e: Pull complete 
ac563158d721: Pull complete 
d2ba16033dad: Pull complete 
688ba7d5c01a: Pull complete 
00e060b6d11d: Pull complete 
1c04857f594f: Pull complete 
4d7cfa90e6ea: Pull complete 
e0431212d27d: Pull complete 
Digest: sha256:e9027fe4d91c0153429607251656806cc784e914937271037f7738bd5b8e7709	# 签名
Status: Downloaded newer image for mysql:latest
docker.io/library/mysql:latest 			# 真实地址
# 以下两个命令等价
docker pull mysql
docker pull docker.io/library/mysql:latest
# 指定版本下载
[root@ziang ~]# docker pull mysql:5.7
5.7: Pulling from library/mysql
72a69066d2fe: Already exists 			# 本地已存在的不再下载
93619dbc5b36: Already exists 
99da31dd6142: Already exists 
626033c43d70: Already exists 
37d5d7efb64e: Already exists 
ac563158d721: Already exists 
d2ba16033dad: Already exists 
0ceb82207cd7: Pull complete 			# 仅下载缺少的
37f2405cae96: Pull complete 
e2482e017e53: Pull complete 
70deed891d42: Pull complete 
Digest: sha256:f2ad209efe9c67104167fc609cca6973c8422939491c9345270175a300419f94
Status: Downloaded newer image for mysql:5.7
docker.io/library/mysql:5.7

删除镜像:docker rmi

# 指定tag删除
[root@ziang ~]# docker rmi -f c20987f18b13
Untagged: mysql:5.7
Untagged: mysql@sha256:f2ad209efe9c67104167fc609cca6973c8422939491c9345270175a300419f94
Deleted: sha256:c20987f18b130f9d144c9828df630417e2a9523148930dc3963e9d0dab302a76
Deleted: sha256:6567396b065ee734fb2dbb80c8923324a778426dfd01969f091f1ab2d52c7989
Deleted: sha256:0910f12649d514b471f1583a16f672ab67e3d29d9833a15dc2df50dd5536e40f
Deleted: sha256:6682af2fb40555c448b84711c7302d0f86fc716bbe9c7dc7dbd739ef9d757150
Deleted: sha256:5c062c3ac20f576d24454e74781511a5f96739f289edaadf2de934d06e910b92
# 删除多个镜像(后面跟多个tag即可)
[root@ziang ~]# docker rmi -f c20987f18b13 feb5d9fea6a5 246db2517862
# 删除所有镜像
[root@ziang ~]# docker rmi -f $(docker images -aq)

3.2 容器命令

说明:有了镜像才可以创建容器,所以需要先下载一个centos镜像:docker pull centos

新建容器并启动:docker run

docker run [可选参数] image

# 可选参数
--name="dockerName" 	容器名,用来区分容器
-d						以后台方式运行
-it						使用交互方式运行,进入容器查看内容
-p						指定容器端口,可以将主机端口映射到容器端口,方式有如下几种
	-p ip:80:8080		主机ip:主机端口:容器端口
	-p 80:8080			主机端口:容器端口(常用)
	-p 8080				容器端口
	8080				容器端口
-P						随机指定端口
# 启动并进入容器
[root@ziang ~]# docker run -it centos /bin/bash # 使用交互式运行centos镜像,进入容器中查看内容。交互运行需要借助控制台,指定使用/bin/bash控制
[root@d034a3a4f9f3 /]# ls	# 查看容器内,由于是基础版本,很多命令是不完善的
bin  etc   lib	  lost+found  mnt  proc  run   srv  tmp  var
dev  home  lib64  media       opt  root  sbin  sys  usr
[root@d034a3a4f9f3 /]# exit	# 退出容器
exit

查看容器:docker ps

[root@ziang ~]# docker ps			# 查看当前正在运行的容器
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES
[root@ziang ~]# docker ps -a		# 查看所有运行的容器(包括曾经运行过的容器)
CONTAINER ID   IMAGE          COMMAND                  CREATED        STATUS                    PORTS     NAMES
d034a3a4f9f3   centos         "/bin/bash"              9 hours ago    Exited (0) 9 hours ago              vibrant_lamport
8b6f1b616774   centos         "/bin/bash"              9 hours ago    Exited (0) 7 hours ago              strange_nash
548b160ded84   feb5d9fea6a5   "/hello"                 10 hours ago   Exited (0) 10 hours ago             optimistic_proskuriakova
483aa315754d   246db2517862   "docker-entrypoint.s…"   8 months ago   Created                             rabbitmq
[root@ziang ~]# docker ps -a -n=1	# 查看最近运行的1个容器
CONTAINER ID   IMAGE     COMMAND       CREATED       STATUS                   PORTS     NAMES
d034a3a4f9f3   centos    "/bin/bash"   9 hours ago   Exited (0) 9 hours ago             vibrant_lamport
[root@ziang ~]# docker ps -aq		# 查看所有运行的容器,-q仅显示容器id
d034a3a4f9f3
8b6f1b616774
548b160ded84
483aa315754d

退出容器:exit

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

删除容器:docker rm

docker rm 容器id			  	    # 删除指定容器id的容器,通过-f参数可删除正在运行的容器
docker rm -f $(docker ps -aq)   # 删除所有容器
docker ps -a -a|xargs docker rm # 删除所有容器

启动和停止容器

docker start 容器id		# 启动容器
docker restart 容器id	# 重启容器
docker stop 容器id		# 停止运行中的容器
docker kill 容器id		# 强制停止容器
[root@ziang ~]# docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES
[root@ziang ~]# docker ps -a
CONTAINER ID   IMAGE     COMMAND       CREATED       STATUS                   PORTS     NAMES
d034a3a4f9f3   centos    "/bin/bash"   9 hours ago   Exited (0) 9 hours ago             vibrant_lamport
[root@ziang ~]# docker start d034a3a4f9f3
d034a3a4f9f3
[root@ziang ~]# docker ps
CONTAINER ID   IMAGE     COMMAND       CREATED       STATUS         PORTS     NAMES
d034a3a4f9f3   centos    "/bin/bash"   9 hours ago   Up 3 seconds             vibrant_lamport
[root@ziang ~]# docker stop d034a3a4f9f3
d034a3a4f9f3
[root@ziang ~]# docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES

docker容器的状态有:运行、停止。run启动容器进入运行状态,stop会让容器停止,rm会让容器消失(删除)

3.3 其他常用命令

后台启动容器

docker run -d 容器image

以该方式启动容器后,使用docker ps命令并没有发现启动的容器,也就是说该容器停止了。docker容器使用后台运行,需要有一个前台进程,docker发现没有前台应用就会自动停止。比如启动一个Nginx,容器启动后发现自己没有提供服务,就会立刻停止

查看容器日志:docker logs

docker logs [可选参数] 容器id

# 可选参数
-tf			# 查看日志,t表示带有时间戳
--tail n	# 显示最后n条日志

Demo:

[root@ziang ~]# docker run -d centos /bin/sh -c "while true;do echo ziang.zhang;sleep 1;done"
08a4ec2e85f9b73090ea5a11955bfaba9df3027f5174b00e52fc5592247697d9
[root@ziang ~]# docker ps
CONTAINER ID   IMAGE     COMMAND                  CREATED         STATUS         PORTS     NAMES
08a4ec2e85f9   centos    "/bin/sh -c 'while t…"   4 seconds ago   Up 3 seconds             cool_hodgkin
[root@ziang ~]# docker logs -tf --tail 10 08a4ec2e85f9
2022-02-03T01:19:31.160489316Z ziang.zhang
2022-02-03T01:19:32.162057672Z ziang.zhang
2022-02-03T01:19:33.163674626Z ziang.zhang
2022-02-03T01:19:34.165353081Z ziang.zhang
2022-02-03T01:19:35.167349305Z ziang.zhang
2022-02-03T01:19:36.169027025Z ziang.zhang
2022-02-03T01:19:37.170892402Z ziang.zhang
2022-02-03T01:19:38.172620267Z ziang.zhang
2022-02-03T01:19:39.174546190Z ziang.zhang
2022-02-03T01:19:40.176468912Z ziang.zhang
2022-02-03T01:19:41.178292254Z ziang.zhang

查看容器中的进程信息:docker top

docker top 容器id
[root@ziang ~]# docker top 08a4ec2e85f9
UID                 PID                 PPID                C                   STIME               TTY                 TIME                CMD
root                4578                4558                0                   09:18               ?                   00:00:00            /bin/sh -c while true;do echo ziang.zhang;sleep 1;done
root                5181                4578                0                   09:27               ?                   00:00:00            /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 1

查看容器元数据:docker inspect

docker inspect 容器id
[root@ziang ~]# docker inspect 08a4ec2e85f9
[
    {
        "Id": "08a4ec2e85f9b73090ea5a11955bfaba9df3027f5174b00e52fc5592247697d9",
        "Created": "2022-02-03T01:18:56.873267955Z",
        "Path": "/bin/sh",
        "Args": [
            "-c",
            "while true;do echo ziang.zhang;sleep 1;done"
        ],
        "State": {
            "Status": "running",
            "Running": true,
            "Paused": false,
            "Restarting": false,
            "OOMKilled": false,
            "Dead": false,
            "Pid": 4578,
            "ExitCode": 0,
            "Error": "",
            "StartedAt": "2022-02-03T01:18:57.079480925Z",
            "FinishedAt": "0001-01-01T00:00:00Z"
        },
        "Image": "sha256:5d0da3dc976460b72c77d94c8a1ad043720b0416bfc16c52c45d4847e53fadb6",
        "ResolvConfPath": "/var/lib/docker/containers/08a4ec2e85f9b73090ea5a11955bfaba9df3027f5174b00e52fc5592247697d9/resolv.conf",
        "HostnamePath": "/var/lib/docker/containers/08a4ec2e85f9b73090ea5a11955bfaba9df3027f5174b00e52fc5592247697d9/hostname",
        "HostsPath": "/var/lib/docker/containers/08a4ec2e85f9b73090ea5a11955bfaba9df3027f5174b00e52fc5592247697d9/hosts",
        "LogPath": "/var/lib/docker/containers/08a4ec2e85f9b73090ea5a11955bfaba9df3027f5174b00e52fc5592247697d9/08a4ec2e85f9b73090ea5a11955bfaba9df3027f5174b00e52fc5592247697d9-json.log",
        "Name": "/cool_hodgkin",
        "RestartCount": 0,
        "Driver": "overlay2",
        "Platform": "linux",
        "MountLabel": "",
        "ProcessLabel": "",
        "AppArmorProfile": "",
        "ExecIDs": null,
        "HostConfig": {
            "Binds": null,
            "ContainerIDFile": "",
            "LogConfig": {
                "Type": "json-file",
                "Config": {}
            },
            "NetworkMode": "default",
            "PortBindings": {},
            "RestartPolicy": {
                "Name": "no",
                "MaximumRetryCount": 0
            },
            "AutoRemove": false,
            "VolumeDriver": "",
            "VolumesFrom": null,
            "CapAdd": null,
            "CapDrop": null,
            "CgroupnsMode": "host",
            "Dns": [],
            "DnsOptions": [],
            "DnsSearch": [],
            "ExtraHosts": null,
            "GroupAdd": null,
            "IpcMode": "private",
            "Cgroup": "",
            "Links": null,
            "OomScoreAdj": 0,
            "PidMode": "",
            "Privileged": false,
            "PublishAllPorts": false,
            "ReadonlyRootfs": false,
            "SecurityOpt": null,
            "UTSMode": "",
            "UsernsMode": "",
            "ShmSize": 67108864,
            "Runtime": "runc",
            "ConsoleSize": [
                0,
                0
            ],
            "Isolation": "",
            "CpuShares": 0,
            "Memory": 0,
            "NanoCpus": 0,
            "CgroupParent": "",
            "BlkioWeight": 0,
            "BlkioWeightDevice": [],
            "BlkioDeviceReadBps": null,
            "BlkioDeviceWriteBps": null,
            "BlkioDeviceReadIOps": null,
            "BlkioDeviceWriteIOps": null,
            "CpuPeriod": 0,
            "CpuQuota": 0,
            "CpuRealtimePeriod": 0,
            "CpuRealtimeRuntime": 0,
            "CpusetCpus": "",
            "CpusetMems": "",
            "Devices": [],
            "DeviceCgroupRules": null,
            "DeviceRequests": null,
            "KernelMemory": 0,
            "KernelMemoryTCP": 0,
            "MemoryReservation": 0,
            "MemorySwap": 0,
            "MemorySwappiness": null,
            "OomKillDisable": false,
            "PidsLimit": null,
            "Ulimits": null,
            "CpuCount": 0,
            "CpuPercent": 0,
            "IOMaximumIOps": 0,
            "IOMaximumBandwidth": 0,
            "MaskedPaths": [
                "/proc/asound",
                "/proc/acpi",
                "/proc/kcore",
                "/proc/keys",
                "/proc/latency_stats",
                "/proc/timer_list",
                "/proc/timer_stats",
                "/proc/sched_debug",
                "/proc/scsi",
                "/sys/firmware"
            ],
            "ReadonlyPaths": [
                "/proc/bus",
                "/proc/fs",
                "/proc/irq",
                "/proc/sys",
                "/proc/sysrq-trigger"
            ]
        },
        "GraphDriver": {
            "Data": {
                "LowerDir": "/var/lib/docker/overlay2/666f081c125b11f2c166ce349a8e6bce578d4720b1b76fdc6afd58b7c6993f43-init/diff:/var/lib/docker/overlay2/ab82fd3f5f7dfd160f732a74032059d85648202a69601a95239ef244ea6a4c3f/diff",
                "MergedDir": "/var/lib/docker/overlay2/666f081c125b11f2c166ce349a8e6bce578d4720b1b76fdc6afd58b7c6993f43/merged",
                "UpperDir": "/var/lib/docker/overlay2/666f081c125b11f2c166ce349a8e6bce578d4720b1b76fdc6afd58b7c6993f43/diff",
                "WorkDir": "/var/lib/docker/overlay2/666f081c125b11f2c166ce349a8e6bce578d4720b1b76fdc6afd58b7c6993f43/work"
            },
            "Name": "overlay2"
        },
        "Mounts": [],
        "Config": {
            "Hostname": "08a4ec2e85f9",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
            ],
            "Cmd": [
                "/bin/sh",
                "-c",
                "while true;do echo ziang.zhang;sleep 1;done"
            ],
            "Image": "centos",
            "Volumes": null,
            "WorkingDir": "",
            "Entrypoint": null,
            "OnBuild": null,
            "Labels": {
                "org.label-schema.build-date": "20210915",
                "org.label-schema.license": "GPLv2",
                "org.label-schema.name": "CentOS Base Image",
                "org.label-schema.schema-version": "1.0",
                "org.label-schema.vendor": "CentOS"
            }
        },
        "NetworkSettings": {
            "Bridge": "",
            "SandboxID": "b3eb26048d3703c07248154ca751b1c05e9cdcdced88e3df18da451914c555fd",
            "HairpinMode": false,
            "LinkLocalIPv6Address": "",
            "LinkLocalIPv6PrefixLen": 0,
            "Ports": {},
            "SandboxKey": "/var/run/docker/netns/b3eb26048d37",
            "SecondaryIPAddresses": null,
            "SecondaryIPv6Addresses": null,
            "EndpointID": "54ca19d0722608eb645ee47d5e07d482b2d5cfe6533591d3cc33e6912e5a14a4",
            "Gateway": "172.17.0.1",
            "GlobalIPv6Address": "",
            "GlobalIPv6PrefixLen": 0,
            "IPAddress": "172.17.0.2",
            "IPPrefixLen": 16,
            "IPv6Gateway": "",
            "MacAddress": "02:42:ac:11:00:02",
            "Networks": {
                "bridge": {
                    "IPAMConfig": null,
                    "Links": null,
                    "Aliases": null,
                    "NetworkID": "7b73a049c8d1d281d8c66fe3dc1471696c813349d7e543123860c0f82c5aba97",
                    "EndpointID": "54ca19d0722608eb645ee47d5e07d482b2d5cfe6533591d3cc33e6912e5a14a4",
                    "Gateway": "172.17.0.1",
                    "IPAddress": "172.17.0.2",
                    "IPPrefixLen": 16,
                    "IPv6Gateway": "",
                    "GlobalIPv6Address": "",
                    "GlobalIPv6PrefixLen": 0,
                    "MacAddress": "02:42:ac:11:00:02",
                    "DriverOpts": null
                }
            }
        }
    }
]

进入正在运行的容器
我们通常使用后台方式运行容器,进入容器可以选择以下两种方式:
方式1:docker exec -it 容器id /bin/bash(常用)
方式2:docker attach 容器id
前者进入容器会开启一个新的终端,后者进入容器正在执行的终端,不会开启新的终端

从容器内拷贝文件到主机

docker cp 容器id:容器路径 主机路径

3.4 小结

学习笔记:云原生容器化技术——Docker_第9张图片

attach		Attach to a running container		   # 当前shell下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		   # 查看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 filesystem image from the contents of a tarball  # 从tar包中的内容创建一个新的文件系统镜像[对应 export]
info		Display system-wide information        # 显示系统相关信息
inspect		Return low-level information on a container	# 查看容器详细信息
kill		Kill a runing container				   # kill指定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退出
logs		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 repository to the docker registry server 	  # 推送指定镜像或库镜像至docker源服务器
restart		Restart a running container.           # 重启运行的容器
rm			Remove one or more container.          # 移除一个或多个容器
rmi			Remove one or more images              # 移除一个或多个镜像[无容器使用该镜像才可删除,否则需要先删除该容器或-f强制删除]
run			Run a command in a new container.      # 创建一个新的容器并运行一个命令
save		Save an image to a tar archive.        # 保存一个镜像为一个tar包[对应 load]
search		Search for an image on the Docker Hub  # 在docker hub中搜索镜像
start		Start a stopped containers			   # 启动容器
stop		Stop a running containers			   # 停止容器
tag		    Tag									   # 查看容器中运行的进程信息
unpause		Unpause a paused container			   # 取消暂停容器
version		Show the docker version informatioins  # 查看docker版本号
wait		Block until a container stops, then print its exit code		  # 截取容器停止时的推出状态值

3.5 练习使用Docker部署Nginx

[root@ziang ~]# docker pull nginx 
Using default tag: latest
latest: Pulling from library/nginx
a2abf6c4d29d: Pull complete 
a9edb18cadd1: Pull complete 
589b7251471a: Pull complete 
186b1aaa4aa6: Pull complete 
b4df32aa5a72: Pull complete 
a0bcbecc962e: Pull complete 
Digest: sha256:0d17b565c37bcbd895e9d92315a05c1c3c9a29f762b011a10c54a66cd53c9b31
Status: Downloaded newer image for nginx:latest
docker.io/library/nginx:latest
[root@ziang ~]# docker images
REPOSITORY   TAG       IMAGE ID       CREATED        SIZE
nginx        latest    605c77e624dd   5 weeks ago    141MB
centos       latest    5d0da3dc9764   4 months ago   231MB
# -d 后台运行
# --name 给容器命名
# -p 宿主机端口:容器内部端口
[root@ziang ~]# docker run -d --name nginx01 -p:3344:80 nginx
f7ff85d30a3099f60b88de8ec4db877ceed5a1b27722ccc5bee4b333cd7c3eb5
[root@ziang ~]# 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>

端口暴露概念
学习笔记:云原生容器化技术——Docker_第10张图片

3.5 可视化工具

  • portainer(先用这个)
  • rancher(CI/CD再用)

什么是portainer?
一个Docker图形化界面管理工具,提供可操作的后台面板。使用以下命令启动potainer:
docker run -d -p 8088:9000 --restart=always -v /var/run/docker.sock:/var/run/docker.sock --privileged=true portainer/potainer
通过浏览器http://ip:8088/访问,可以看到如下登陆界面:
学习笔记:云原生容器化技术——Docker_第11张图片
进入之后就可以根据可视化面板控制


四、Docker镜像

4.1 镜像是什么

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

如何得到镜像:

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

4.2 Docker镜像加载原理

UnionFS(联合文件系统)

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

Docker镜像加载原理

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

dootfs(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、/etc等标准目录和文件。rootfs就是各种不同的操作系统发行版,比如Ubuntu、CentOS等等。
学习笔记:云原生容器化技术——Docker_第12张图片
平时我们安装进虚拟机的CentOS大概几个G大小,但为什么Docker的镜像只有200M?
对于一个精简的OS,rootfs可以很小,只需要包含最基本的命令、工具和程序库就可以了,因为底层直接用Host的kernel,自己只需要提供rootfs就可以了。由此可见对于不同的Linux发行版,rootfs基本是一致的,rootfs会有差别,因此不同的发行版可以共用bootfs。

4.3 分层的理解

下载镜像观察打印的日志输出,可以看出镜像是一层一层下载的

[root@ziang ~]# docker pull redis
Using default tag: latest
latest: Pulling from library/redis
a2abf6c4d29d: Already exists 
c7a4e4382001: Pull complete 
4044b9ba67c9: Pull complete 
c8388a79482f: Pull complete 
413c8bb60be2: Pull complete 
1abfd3011519: Pull complete 
Digest: sha256:db485f2e245b5b3329fdc7eff4eb00f913e09d8feb9ca720788059fdc2ed8339
Status: Downloaded newer image for redis:latest
docker.io/library/redis:latest

理解

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

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

该镜像当前已经包含3个镜像层,如下图所示(这只是一个用于演示的很简单的例子)。
学习笔记:云原生容器化技术——Docker_第13张图片
在添加额外镜像层的同时,镜像始终保持是当前所有镜像的组合,理解这一点非常重要。下图中举了一个简单的例子,每个镜像层包含3个文件,而镜像包含了来自两个镜像层的6个文件。
学习笔记:云原生容器化技术——Docker_第14张图片
上图的镜像层跟之前图中的略有区别,主要目的是便于展示文件。

下图中展示了一个稍微复杂的三层镜像,在外部看来整个镜像只有6个文件,这是因为最上层中的文件7是文件5的一个更新版本。
学习笔记:云原生容器化技术——Docker_第15张图片
这种情况下,上层镜像层中文件覆盖了底层镜像层中的文件。这样就使得文件的更新版本作为一个新镜像层添加到镜像当中。

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

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

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

下图展示了与系统展示相同的三层镜像。所有镜像层堆叠并合并,对外提供统一的视图。
学习笔记:云原生容器化技术——Docker_第16张图片

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

4.4 commit镜像

 docker commit  # 提交容器成为一个新的副本
 docker commit -m="commit note" -a="author" 容器id 目标镜像名:[TAG]  # 命令和git类似

Demo:

# 1.启动一个tomcat容器
[root@ziang ~]# docker ps
CONTAINER ID   IMAGE     COMMAND                  CREATED         STATUS         PORTS                    NAMES
7d7f032ea599   tomcat    "catalina.sh run"        9 minutes ago   Up 2 minutes   0.0.0.0:8080->8080/tcp   nervous_maxwell
f7ff85d30a30   nginx     "/docker-entrypoint.…"   7 days ago      Up 7 days      0.0.0.0:3344->80/tcp     nginx01
08a4ec2e85f9   centos    "/bin/sh -c 'while t…"   7 days ago      Up 7 days                               cool_hodgkin
[root@ziang ~]# docker exec -it 7d7f0 /bin/bash
root@7d7f032ea599:/usr/local/tomcat# ls webappps
# 2.tomcat官方镜像默认webapps目录下是空的,拷贝基本文件到webapps目录下
root@7d7f032ea599:/usr/local/tomcat# ls
BUILDING.txt  CONTRIBUTING.md  LICENSE	NOTICE	README.md  RELEASE-NOTES  RUNNING.txt  bin  conf  lib  logs  native-jni-lib  temp  webapps  webapps.dist  work
root@7d7f032ea599:/usr/local/tomcat# cp -r webapps.dist/* webapps
root@7d7f032ea599:/usr/local/tomcat# ls webapps
ROOT  docs  examples  host-manager  manager
# 3.将操作过的容器commit为一个镜像。以后可以使用该镜像启动容器
[root@ziang ~]# docker commit -a="ziang.zhang" -m="add some files to webapps" 7d7f03 tomcat.ziang.1.0
sha256:3418d38b10501944949f7230ad332d930e149a20294ee7f4e92d05b4ebd262e9
# 4.查看刚刚提交的镜像tomcat.ziang.1.0,发现它比tomcat大13MB,这就是cp操作后的结果
[root@ziang ~]# docker images
REPOSITORY            TAG       IMAGE ID       CREATED         SIZE
tomcat.ziang.1.0      latest    3418d38b1050   9 seconds ago   693MB
nginx                 latest    605c77e624dd   6 weeks ago     141MB
tomcat                latest    fb5657adc892   7 weeks ago     680MB
redis                 latest    7614ae9453d1   7 weeks ago     113MB
centos                latest    5d0da3dc9764   4 months ago    231MB
portainer/portainer   latest    580c0e4e98b0   10 months ago   79.1MB

如果想保存容器的状态,就可以通过commit来提交,获得一个新镜像

学完以上命令,Docker学习才正式入门


五、容器数据卷

5.1 什么是容器数据卷

Docker将应用与环境打包成镜像,通过镜像启动容器。思考两个问题:

  1. 当启动一个mysql容器,在mysql中存储了大量数据,如果此时将该容器kill掉,那么容器中存储的数据将会丢失
  2. 当需要频繁修改容器中的配置文件时,每次都需要进入该容器进行修改,会比较麻烦

所以Docker应该有一个持久化和同步数据的机制,将容器中产生的数据同步到本地,这个机制就是容器数据卷,将容器内的目录挂在到本地目录
学习笔记:云原生容器化技术——Docker_第17张图片
使用容器数据卷技术,可以将主机目录与容器内目录进行挂载,在其中一个目录更新了内容,另一个目录就会进行同步更新。另外,只要该容器存在,无论启动与否,数据的同步仍在进行。如果该容器被rm,那么数据将依然存在,但同步将不再

总结:容器数据卷是容器数据的持久化和同步技术,各个容器之间也可以使用该技术。

5.2 容器数据卷使用方式一:参数-v

方式一:启动容器时使用-v参数

docker run -it -v 主机目录1:容器目录1 -v 主机目录2:容器目录2 ...

实战:安装MySQL并使用容器数据卷

1.docker pull mysql:5.7

# 参数
-d 后台启动
-p 端口暴露
-v 数据卷挂载
-e 环境变量配置
--name 容器命名
2.docker run -d -p 3306:3306 -v /home/mysql/conf:/etc/mysql/conf.d -v /home/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql:5.7

3.启动成功后,使用MySQL图形界面连接到服务器的3306端口,创建一个数据库并在其中创建表进行插入操作

4.去服务器/home/mysql/data目录下查看是否创建了该目录(数据库)与文件(表)

宿主机的挂载目录与容器中的挂载目录不存在时都会自动创建

5.3 具名挂载与匿名挂载

# 匿名挂载:-v 容器目录(仅指定容器目录)
[root@ziang ~]# docker run -d -P -v /etc/nginx --name nginx02 nginx # -P 随机指定端口
61dacb811c228b36fea583509bd303dcc2c22647631e6cfe2ca780c353bb29ef
# 查看所有容器数据卷情况,每一条数据代表一个真实存在的目录
[root@ziang ~]# docker volume ls
DRIVER    VOLUME NAME
local     26cd6fb4a595803c408f4b43f2fb97ca46df35a2ca6634ee3dded63a5b7ed235
local     922e29647b7fcc546841088a0e9580e79c849cd669096ce306cd2c74b4d464a0
local     62326bf1e0e8601ca8e2f0961d54deae6de13d05a605b1a242551592a1a36236
local     d7331eebf78e6fe7e5793efc256a3dacec290d698c28fd6eabc98a0a06b6176d
local     e5300d1e74f17909816fc94b1445e7e686d27283fff2047d7128026392dad324

# 具名挂载:-v 卷名/容器目录
[root@ziang ~]# docker run -d -P -v juming-nginx:/etc/nginx --name nginx03 nginx
59d2cc2ba71fb03c01a7beb42ced116345498ecf25a60c43a411ec395aeb3dd8
[root@ziang ~]# docker volume ls
DRIVER    VOLUME NAME
local     26cd6fb4a595803c408f4b43f2fb97ca46df35a2ca6634ee3dded63a5b7ed235
local     922e29647b7fcc546841088a0e9580e79c849cd669096ce306cd2c74b4d464a0
local     62326bf1e0e8601ca8e2f0961d54deae6de13d05a605b1a242551592a1a36236
local     d7331eebf78e6fe7e5793efc256a3dacec290d698c28fd6eabc98a0a06b6176d
local     e5300d1e74f17909816fc94b1445e7e686d27283fff2047d7128026392dad324
local     juming-nginx
# 查看目录位置(在没有指定目录的情况下,所有挂载的目录都在/var/lib/docker/volumes/下)
[root@ziang ~]# docker volume inspect juming-nginx
[
    {
        "CreatedAt": "2022-02-15T23:20:50+08:00",
        "Driver": "local",
        "Labels": null,
        "Mountpoint": "/var/lib/docker/volumes/juming-nginx/_data",
        "Name": "juming-nginx",
        "Options": null,
        "Scope": "local"
    }
]

通过具名挂载可以方便地找到该卷,多数情况下使用具名挂载

如何确认使用何种方式挂载?

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

拓展:

# -v 容器内路径:ro
ro readonly   只读,数据只能在外部改变,容器内部只能读数据
docker run -d -P -v juming-nginx:/etc/nginx:ro --name nginx03 nginx

# -v 容器内路径:rw
rw readrwrite  可写,数据可以在外部改变,也可以在内部改变
docker run -d -P -v juming-nginx:/etc/nginx:rw --name nginx03 nginx

# 一旦设置了该权限,挂载出来的内容就会存在限定。
# 只要看到ro,就说明该目录内容只能由宿主机来操作,容器内部无法操作

5.4 容器数据卷使用方式二:Dockerfile

DockerFile是用来构建docker镜像的文件,内容是命令脚本,可以通过它生成镜像。
镜像是一层一层的结构,而DockerFile的每一行命令就对应其中一层

[root@ziang containerDataVolume]# vim dockerfile1
[root@ziang containerDataVolume]# cat dockerfile1 
FROM centos							# 使用基础镜像

VOLUME ["volume01","volume02"]		# 挂载数据卷(匿名挂载)

CMD echo "----- end -----"			# 执行
CMD /bin/bash
# -f dockerfile路径;-t 镜像名
[root@ziang containerDataVolume]# docker build -f dockerfile1 -t ziangTest/centos .
Sending build context to Docker daemon  4.608kB
Step 1/4 : FROM centos
 ---> 5d0da3dc9764
Step 2/4 : VOLUME ["volume01","volume02"]
 ---> Running in 914d32002e92
Removing intermediate container 914d32002e92
 ---> a45fc8e2da0a
Step 3/4 : CMD echo "----- end -----"
 ---> Running in d574aa3ce16b
Removing intermediate container d574aa3ce16b
 ---> cff2dd066931
Step 4/4 : CMD /bin/bash
 ---> Running in e44806b5d641
Removing intermediate container e44806b5d641
 ---> e3771927547f
Successfully built e3771927547f
Successfully tagged ziangTest/centos:latest
[root@ziang containerDataVolume]# docker images
REPOSITORY            TAG       IMAGE ID       CREATED         SIZE
ziangTest/centos      latest    e3771927547f   4 minutes ago   231MB
tomcat.ziang.1.0      latest    3418d38b1050   5 days ago      693MB
nginx                 latest    605c77e624dd   6 weeks ago     141MB
tomcat                latest    fb5657adc892   7 weeks ago     680MB
redis                 latest    7614ae9453d1   8 weeks ago     113MB
mysql                 latest    3218b38490ce   8 weeks ago     516MB
centos                latest    5d0da3dc9764   5 months ago    231MB
portainer/portainer   latest    580c0e4e98b0   11 months ago   79.1MB
[root@ziang ~]# docker run -it ziangTest/centos /bin/bash
[root@547072811dc7 /]# ls -l
total 56
lrwxrwxrwx   1 root root    7 Nov  3  2020 bin -> usr/bin
drwxr-xr-x   5 root root  360 Feb 16 13:28 dev
drwxr-xr-x   1 root root 4096 Feb 16 13:28 etc
drwxr-xr-x   2 root root 4096 Nov  3  2020 home
lrwxrwxrwx   1 root root    7 Nov  3  2020 lib -> usr/lib
lrwxrwxrwx   1 root root    9 Nov  3  2020 lib64 -> usr/lib64
drwx------   2 root root 4096 Sep 15 14:17 lost+found
drwxr-xr-x   2 root root 4096 Nov  3  2020 media
drwxr-xr-x   2 root root 4096 Nov  3  2020 mnt
drwxr-xr-x   2 root root 4096 Nov  3  2020 opt
dr-xr-xr-x 110 root root    0 Feb 16 13:28 proc
dr-xr-x---   2 root root 4096 Sep 15 14:17 root
drwxr-xr-x  11 root root 4096 Sep 15 14:17 run
lrwxrwxrwx   1 root root    8 Nov  3  2020 sbin -> usr/sbin
drwxr-xr-x   2 root root 4096 Nov  3  2020 srv
dr-xr-xr-x  13 root root    0 Feb 16 13:28 sys
drwxrwxrwt   7 root root 4096 Sep 15 14:17 tmp
drwxr-xr-x  12 root root 4096 Sep 15 14:17 usr
drwxr-xr-x  20 root root 4096 Sep 15 14:17 var
drwxr-xr-x   2 root root 4096 Feb 16 13:28 volume01		# 挂载目录1
drwxr-xr-x   2 root root 4096 Feb 16 13:28 volume02		# 挂载目录2
[root@73216b2be2dd volume01]# exit             
exit
[root@ziang ~]# docker inspect 73216b2be2dd
# 在Mounts中可看到该容器的数据卷挂载信息

这种方式比较常见,可以在构建自己的镜像时进行卷挂载;若没有中构建镜像时挂载,则可以在启动容器的时候使用-v参数进行挂载

5.5 数据卷容器

学习笔记:云原生容器化技术——Docker_第18张图片
Demo:

[root@ziang ~]# docker run -it --name dockerA ziang/centos 
[root@ziang ~]# docker run -it --name dockerB --volumes-from dockerA ziang/centos
[root@ziang ~]# docker ps
CONTAINER ID   IMAGE          COMMAND                  CREATED              STATUS              PORTS     NAMES
f406eff2f33c   ziang/centos   "/bin/sh -c /bin/bash"   39 seconds ago       Up 38 seconds                 dockerB
671c33eb072f   ziang/centos   "/bin/sh -c /bin/bash"   About a minute ago   Up About a minute             dockerA
[root@ziang ~]# docker attach 671c33eb072f
[root@671c33eb072f /]# ls
bin  etc   lib	  lost+found  mnt  proc  run   srv  tmp  var	   volume02
dev  home  lib64  media       opt  root  sbin  sys  usr  volume01
[root@671c33eb072f /]# cd volume01
[root@671c33eb072f volume01]# touch abc.java
[root@671c33eb072f volume01]# read escape sequence	  # ctrl + p + q
[root@ziang ~]# docker attach f406eff2f33c
[root@f406eff2f33c /]# cd volume01
[root@f406eff2f33c volume01]# ls
abc.java    # dockerA创建的文件同步到了dockerB,相当于A被B继承,A就是数据卷容器
[root@ziang ~]# docker run -it --name dockerC --volumes-from dockerA ziang/centos
[root@aaf87d82d739 /]# ls
bin  etc   lib	  lost+found  mnt  proc  run   srv  tmp  var	   volume02
dev  home  lib64  media       opt  root  sbin  sys  usr  volume01
[root@aaf87d82d739 /]# cd volume01
[root@aaf87d82d739 volume01]# ls
abc.java	# 再创建一个dockerC同步挂载dockerA,该文件也存在
[root@ziang ~]# docker rm -f 671c33eb072f
671c33eb072f
[root@ziang ~]# docker attch f406eff2f33c
docker: 'attch' is not a docker command.
See 'docker --help'
[root@ziang ~]# docker attach f406eff2f33c
[root@f406eff2f33c volume01]# ls
abc.java    #  删除dockerA,其他容器仍存在该文件

对多个MySQL容器进行数据同步

[root@ziang ~]# docker run -d -p 3345:3306 --name mysqlA -v /etc/mysql/conf.d -v /var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 mysql:5.7
[root@ziang ~]# docker run -d -p 3346:3306 --name mysqlB -e MYSQL_ROOT_PASSWORD=123456 --volumes-from mysqlA mysql:5.7

总结:可以实现容器间配置信息的传递,数据卷容器的生命周期一直持续到没有容器使用为止


六、DockerFile

6.1 DockerFile介绍

Dockerfile是用来构建Docker镜像的文件,一个命令参数脚本

构建步骤:

  1. 编写一个Dockerfile文件
  2. docker build 构建为一个镜像
  3. docker run 运行镜像
  4. docker push 发布到DockerHub或阿里云镜像仓库

学习笔记:云原生容器化技术——Docker_第19张图片
学习笔记:云原生容器化技术——Docker_第20张图片
很多官方镜像都是基础包,很多功能没有,需要用户按需求搭建自己的镜像

6.2 DockerFile构建过程

基础知识

  1. 关键字指令单词是大写的
  2. 执行顺序自上而下
  3. ‘#’ 表示注释
  4. 每条指令都会创建一个新的镜像层并提交


DockerFile是面向开发的,以后要发布项目做镜像,就需要编写DockerFile文件,这个文件十分简单
Docker镜像逐渐成为企业交付的标准

  • DockerFile:构建文件,定义了一切的步骤,源代码
  • DockerImages:通过DockerFile构建生成的镜像,最终发布和运行的产品
  • DockerContainer:容器是由镜像运行起来提供服务的

6.3 DockerFile命令

FROM 			# 基础镜像,一切从这里开始构建
MAINTAINER		# 镜像是由谁编写的,姓名+邮箱
RUN				# 镜像构建时需要运行的命令
ADD				# 构建步骤,比如搭建一个tomcat镜像,需要加入一个tomcat的压缩包,即添加内容
WORKDIR			# 镜像的工作目录
VOLUME			# 设置容器卷,挂载的目录
EXPOSE			# 暴露端口,写了该参数就不需要在run -p中指定端口
CMD				# 指定该容器启动时(docker run)要运行的命令,只有最后一个会生效,可被替代
ENTRYPOINT		# 指定该容器启动时(docker run)要运行的命令,可以追加命令
ONBUILD			# 当构建一个被继承的DockerFile,这个时候会运行 ONBUILD的指令(触发指令)
COPY			# 类似ADD,将文件拷贝到镜像中
ENV				# 构建时设置环境变量

学习笔记:云原生容器化技术——Docker_第21张图片

6.4 实战测试

DockerHub中99%的镜像都是从基础镜像scratch开始的,然后添加需要的配置和软件进行构建
学习笔记:云原生容器化技术——Docker_第22张图片
Demo:

# 1.编写Dockerfile文件
[root@ziang dockerfile]# cat dockerfile-mycentoscat dockerfile-mycentos
FROM centos						# 从centos开始构建
MAINTAINER ziangzhang<[email protected]>		# 构建人信息

ENV MYPATH /use/local			# 设置环境变量
WORKDIR $MYPATH					# 工作目录(一进入镜像就会首先在工作目录)

RUN yum -y install vim			# 下载vim
RUN yum -y install net-tools	# 下载net-tools

EXPOSE 80						# 暴露端口

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

# 2.通过文件构建镜像
# docker build -f dockerfile文件路径 -t 镜像仓库/镜像名(镜像名称:版本号)
[root@ziang dockerfile]# cat dockerfile-mycentosdocker build -f dockerfile-mycentos -t mycentos:0.1 .

列出镜像的变更历史:docker history 镜像id/镜像名

6.4 CMD与ENTRYPOINT的区别

CMD				# 指定该容器启动时(docker run)要运行的命令,只有最后一个会生效,可被替代
ENTRYPOINT		# 指定该容器启动时(docker run)要运行的命令,可以追加命令

Demo:

# CMD
[root@ziang dockerfile]# cat dockerfile-cmd-test 
FROM tomcat
CMD ["ls","-a"]
[root@ziang dockerfile]# docker build -f dockerfile-cmd-test -t dockerfile-cmd:0.1 .
Sending build context to Docker daemon  4.096kB
Step 1/2 : FROM tomcat
 ---> fb5657adc892
Step 2/2 : CMD ["ls","-a"]
 ---> Using cache
 ---> 9e26f3ba0a87
Successfully built 9e26f3ba0a87
Successfully tagged dockerfile-cmd:0.1
[root@ziang dockerfile]# docker run dockerfile-cmd:0.1
.
..
BUILDING.txt
CONTRIBUTING.md
LICENSE
NOTICE
README.md
RELEASE-NOTES
RUNNING.txt
bin
conf
lib
logs
native-jni-lib
temp
webapps
webapps.dist
work
# 想在运行该容器时追加一个命令-l想达到ls -al的效果,但在CMD下-l替换了CMD ["ls","-a"],-l并非命令,所以报错
[root@ziang dockerfile]# docker run dockerfile-cmd:0.1 -l
docker: Error response from daemon: OCI runtime create failed: container_linux.go:380: starting container process caused: exec: "-l": executable file not found in $PATH: unknown.
ERRO[0000] error waiting for container: context canceled

# ENTRYPOINT
[root@ziang dockerfile]# cat dockerfile-entrypoint-test
FROM tomcat
ENTRYPOINT ["ls","-a"]
[root@ziang dockerfile]# docker build -f dockerfile-entrypoint-test -t dockerfile-entrypoint:0.1 .
Sending build context to Docker daemon  4.096kB
Step 1/2 : FROM tomcat
 ---> fb5657adc892
Step 2/2 : ENTRYPOINT ["ls","-a"]
 ---> Running in 43fa27dc91b0
Removing intermediate container 43fa27dc91b0
 ---> e95e71dd650b
Successfully built e95e71dd650b
Successfully tagged dockerfile-entrypoint:0.1
[root@ziang dockerfile]# docker run dockerfile-entrypoint:0.1
.
..
BUILDING.txt
CONTRIBUTING.md
LICENSE
NOTICE
README.md
RELEASE-NOTES
RUNNING.txt
bin
conf
lib
logs
native-jni-lib
temp
webapps
webapps.dist
work
[root@ziang dockerfile]# docker run dockerfile-entrypoint:0.1 -l
total 168
drwxr-xr-x 1 root root  4096 Dec 22 17:07 .
drwxr-xr-x 1 root root  4096 Dec 22 17:00 ..
-rw-r--r-- 1 root root 18994 Dec  2 22:01 BUILDING.txt
-rw-r--r-- 1 root root  6210 Dec  2 22:01 CONTRIBUTING.md
-rw-r--r-- 1 root root 60269 Dec  2 22:01 LICENSE
-rw-r--r-- 1 root root  2333 Dec  2 22:01 NOTICE
-rw-r--r-- 1 root root  3378 Dec  2 22:01 README.md
-rw-r--r-- 1 root root  6905 Dec  2 22:01 RELEASE-NOTES
-rw-r--r-- 1 root root 16517 Dec  2 22:01 RUNNING.txt
drwxr-xr-x 2 root root  4096 Dec 22 17:07 bin
drwxr-xr-x 2 root root  4096 Dec  2 22:01 conf
drwxr-xr-x 2 root root  4096 Dec 22 17:06 lib
drwxrwxrwx 2 root root  4096 Dec  2 22:01 logs
drwxr-xr-x 2 root root  4096 Dec 22 17:07 native-jni-lib
drwxrwxrwx 2 root root  4096 Dec 22 17:06 temp
drwxr-xr-x 2 root root  4096 Dec 22 17:06 webapps
drwxr-xr-x 7 root root  4096 Dec  2 22:01 webapps.dist
drwxrwxrwx 2 root root  4096 Dec  2 22:01 work

6.5 实战:制作Tomcat镜像

1 准备镜像文件:Tomcat压缩包,JDK压缩包
2 编写Dockerfile,官方命名即Dockerfile,docker build会自动寻找该命名的文件,无需再通过-f参数指定

FROM centos
MAINTAINER ziang.zhang

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

ADD apache-tomcat-9.0.33.tar.gz /usr/local/
ADD jdk-8u65-linux-x64.rpm /usr/local/

RUN yum -y install vim

ENV MYWORKPATH /usr/local
ENV JAVA_HOME /usr/local/jdk1.8.0_65
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/toos.jar
ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.33
ENV CATALINA_BASH /usr/local/apache-tomcat-9.0.33
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin

WORKDIR $MYWORKPATH

EXPOSE 8080

CMD /usr/local/apache-tomcat-9.0.33/bin/startup.sh && tail -F /usr/local/apache-tomcat-9.0.33/bin/logs/catalina.out
[root@ziang zhangziang]# ls
apache-tomcat-9.0.33.tar.gz  readme.txt
Dockerfile                   redis-6.0.6.tar.gz
jdk-8u65-linux-x64.rpm
[root@ziang zhangziang]# vim Dockerfile
[root@ziang zhangziang]# cat Dockerfile
FROM centos
MAINTAINER ziang.zhang<[email protected]>

COPY readme.txt /usr/local/readme.txt
COPY jdk-8u65-linux-x64.rpm /usr/local/

ADD apache-tomcat-9.0.33.tar.gz /usr/local/

RUN yum -y install vim
RUN rpm -ivh /usr/local/jdk-8u65-linux-x64.rpm

ENV MYWORKPATH /usr/local
ENV JAVA_HOME /usr/java/jdk1.8.0_65
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/toos.jar
ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.33
ENV CATALINA_BASH /usr/local/apache-tomcat-9.0.33
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin

WORKDIR $MYWORKPATH

EXPOSE 8080

CMD /usr/local/apache-tomcat-9.0.33/bin/startup.sh && tail -F /usr/local/apache-tomcat-9.0.33/bin/logs/catalina.out
[root@ziang zhangziang]# docker build -t zomcat:0.1 .
[root@ziang zhangziang]# docker images
REPOSITORY              TAG       IMAGE ID       CREATED          SIZE
zomcat               0.1       49635e747d1d   2 minutes ago    407MB
# 挂载数据卷时,宿主机与容器中没有的目录会自动创建。挂载webapps目录后,发布的项目可以直接放置在本地
[root@ziang zhangziang]# docker run -d -p 9090:8080 --name ziangtomcat -v /home/zhangziang/tomcat/webapps:/usr/local/apache-tomcat-9.0.33/webapps/test -v /home/zhangziang/tomcat/logs:/usr/local/apache-tomcat-9.0.33/logs zomcat:0.1

6.6 发布自己的镜像

发布到DockerHub

  1. 前往DockerHubhttps://hub.docker.com/,注册自己的账号
  2. 使用docker login命令进行登陆
  3. 使用docker push命令将自己的镜像发布到DockerHub中

发布到阿里云镜像仓库

  1. 登陆阿里云找到容器镜像服务
  2. 创建命名空间和镜像仓库
  3. 进入镜像仓库可查看使用步骤
    学习笔记:云原生容器化技术——Docker_第23张图片
相关命令:
$ docker login --username=tz**** registry.cn-hangzhou.aliyuncs.com
$ docker tag [ImageId] registry.cn-hangzhou.aliyuncs.com/ziang_repository/demo01:[镜像版本号]
$ docker push registry.cn-hangzhou.aliyuncs.com/ziang_repository/demo01:[镜像版本号]
$ docker pull registry.cn-hangzhou.aliyuncs.com/ziang_repository/demo01:[镜像版本号]

Docker命令小结

七、Docker网络原理

7.1 理解docker0

在服务器运行ip addr命令,可以看到以下 3 个网卡
学习笔记:云原生容器化技术——Docker_第24张图片
三个网络分别代表三种环境,那么Docker是如何处理容器网络访问的?

首先思考两个问题:

  1. 本机是否能ping通容器的ip
  2. 容器是否能ping通另一个容器的ip

答案是可以的。服务器安装docker后会有一个新网卡docker0(桥接模式),使用的技术是evth-pair,每启动一个docker容器,就会给docker容器分配一个ip。

docker run启动一个容器后再次查看ip地址,会发现出现了一个新的网卡。当进入该容器后运行ip addr命令,会再次看到该网卡,也就是说容器内外都可以见到此网卡:
在这里插入图片描述
再次启动一个容器后:
在这里插入图片描述
通过以上实验可以看出,网卡是成对的。evth-pair就是一对虚拟设备接口,一端连着协议,一端彼此相连,正因为有这个特性evth-pair通常被充当为一个桥梁,连接各种虚拟网络设备。比如OpenStack、Docker容器间的连接、OVS的连接,都是使用evth-pair技术。
学习笔记:云原生容器化技术——Docker_第25张图片

结论:tomcat01与tomcat02共用同一个路由器:docker0,所有容器不指定网络的情况下,都是docker0路由的,Docker会给我们的容器分配一个默认的可用IP

小结:Docker使用Linux的桥接,宿主机的docker0作为docker容器的网桥。Docker中所有的网络接口都是虚拟的,转发效率高。一旦删除容器,相应的一对网桥也就消失


八、IDEA整合Docker


九、Docker Compose


十、Docker Swarm


十一、CI\CD Jenkins


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