Docker概述

Docker为什么会出现?

一款应用从开发到上线,一般会有开发环境、测试环境和生产环境

Docker的出现是为了解决不同环境中应用开发、测试和部署时配置重复且繁琐,且环境不同引发应用出现崩溃、不兼容的问题,Docker通过隔离机制,将应用运行的必要环境和应用打包在一起,可以让应用轻松、快速地部署成功

Docker历史

2010年,dotCloud公司创始人Solomon Hykes发起了Docker项目,2013年,Docker项目开源。Docker使用Go语言进行开发实现,对进程进行封装隔离,是属于操作系统层面的虚拟化技术

由于隔离的进程独立于宿主和其他的隔离的进程,因此也称其为容器。

Docker为什么会流行?

Docker是一个开源的引擎,可以轻松的为任何应用创建一个轻量级、可移植的、自给自足的容器。开发者在笔记本上编译测试通过的容器可以批量地在生产环境中部署,包括VMs(虚拟机)、bare metal、OpenStack集群和其他的基础应用平台。

Docker可以解决的问题:

  • 上线流程繁琐,需要经历开发->测试->申请资源->审批->部署->测试等环节
  • 资源利用率低,普通服务器利用率低,造成过多浪费
  • 扩容/缩容不及时,业务高峰期扩容流程繁琐,上线不及时
  • 服务环境臃肿,对维护、迁移带来困难
  • 环境不一致

Docker常用于如下场景:

  • Web应用的自动打包和发布;
  • 自动化测试的持续集成、发布;
  • 在服务型环境中部署和调整数据库或其他的后台应用;
  • 从头编译或扩展现有的OpenShift或Cloud Foundry平台来搭建自己的PaaS服务。

Docker资料

虚拟机VS容器

传统虚拟机:虚拟出一套硬件后,在其上运行一个完整的操作系统,然后在这个系统安装和运行软件。

传统虚拟化

Docker:应用直接运行在宿主机的内核,容器没有自己的内核,也没有虚拟硬件,所以更轻量,每个容器间是互相隔离,每个容器内都有一个属于自己的文件系统,互不影响。

Docker

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

Containers VS VM

Docker容器VM传统虚拟机
虚拟化类型操作系统虚拟化硬件虚拟化
性能=宿主机性能5%-20%损耗
隔离性NS隔离
QoSCgroup弱
安全性

Docker基本组成

Docker基本组成

Docker名词

镜像 image:Docker镜像好比一个模板,可以通过这个模板来创建容器服务,如:tomcat镜像–>docker run–>tomcat01容器,通过这个镜像可以创建多个容器。

容器 container:Docker利用容器技术,以镜像为模板来创建独立运行的一个或一组应用,容器有启动、停止、删除等基本命令。

仓库 repository:Docker仓库是存放镜像的地方,仓库分为公有仓库和私有仓库,公有仓库有:Docker Hub(默认放在国外),阿里云代理(配置镜像加速)。

Docker安装

环境准备

1、需要会Linux基本指令

2、一台服务器(本文使用阿里云服务器,宿主机操作系统是CentOS 7)

3、连接远程服务器进行操作(本文使用的远程连接软件是SecureCRT)

环境查看

# 系统内核是 3.10 以上的
[root@xizou /]# uname -r
3.10.0-1160.76.1.el7.x86_64

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

安装Docker

帮助文档 https://docs.docker.com/engine/install/centos/

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

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

# 3.设置镜像的仓库
yum-config-manager \
--add-repo \
https://download.docker.com/linux/centos/docker-ce.repo # 默认是国外的

# 推荐设置阿里云的镜像仓库
yum-config-manager \
--add-repo \
http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

# 更新软件包索引
yum makecache fast

# 4.安装docker docker-ce指社区版 docker-ee指企业版
yum install docker-ce docker-ce-cli containerd.io docker-compose-plugin

# 5.启动docker
systemctl start docker

# 6.使用docker version查看是否安装成功
[root@xizou /]# docker version
Client: Docker Engine - Community
Version: 20.10.21
API version: 1.41
Go version: go1.18.7
Git commit: baeda1f
Built: Tue Oct 25 18:04:24 2022
OS/Arch: linux/amd64
Context: default
Experimental: true

Server: Docker Engine - Community
Engine:
Version: 20.10.21
API version: 1.41 (minimum version 1.12)
Go version: go1.18.7
Git commit: 3056208
Built: Tue Oct 25 18:02:38 2022
OS/Arch: linux/amd64
Experimental: false
containerd:
Version: 1.6.9
GitCommit: 1c90a442489720eec95342e1789ee8a5e1b9536f
runc:
Version: 1.1.4
GitCommit: v1.1.4-0-g5fd4c4d
docker-init:
Version: 0.19.0
GitCommit: de40ad0

# 7.测试
[root@xizou /]# docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
2db29710123e: Pull complete
Digest: sha256:e18f0a777aefabe047a671ab3ec3eed05414477c951ab1a6f352a06974245fe7
Status: Downloaded newer image for hello-world:latest

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

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

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

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

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

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

run的运行流程图

卸载Docker

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

# 2.删除资源
rm -rf /var/lib/docker
rm -rf /var/lib/containerd

配置阿里云镜像加速(前提是购买了阿里云服务器)

登陆阿里云–>阿里云控制台–>搜索容器镜像服务–>点击容器镜像服务–>点击镜像工具的镜像加速器–>按照CentOS页签下的教程在服务器里配置容器镜像加速

sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://2tq3dbmj.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker

底层原理

Docker是怎么工作的?

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

Docker工作示意图

Docker命令

帮助命令

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

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

镜像命令

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

[root@xizou /]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest feb5d9fea6a5 13 months ago 13.3kB

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

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

docker search 搜索镜像

[root@xizou /]# docker search mysql
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
mysql MySQL is a widely used, open-source relation… 13400 [OK]
mariadb MariaDB Server is a high performing open sou… 5113 [OK]

# 可选项
-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@xizou /]# docker search mysql --filter=STARS=300
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
mysql MySQL is a widely used, open-source relation… 13400 [OK]
mariadb MariaDB Server is a high performing open sou… 5113 [OK]
phpmyadmin phpMyAdmin - A web interface for MySQL and M… 669 [OK]
percona Percona Server is a fork of the MySQL relati… 592 [OK]

docker pull 镜像名[:tag] 下载镜像

[root@xizou /]# 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 docker.io/library/mysql:latest

# 指定版本下载
[root@xizou /]# docker pull mysql:5.7
5.7: Pulling from library/mysql
72a69066d2fe: Already exists # 分层下载,已经存在的layers不会重复下载
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

# 查看所有镜像
[root@xizou /]# docker images -a
REPOSITORY TAG IMAGE ID CREATED SIZE
mysql 5.7 c20987f18b13 10 months ago 448MB
mysql latest 3218b38490ce 10 months ago 516MB
hello-world latest feb5d9fea6a5 13 months ago 13.3kB

docker rmi 删除镜像

[root@xizou /]# docker rmi -f 镜像id 				   # 删除指定的镜像
[root@xizou /]# docker rmi -f 镜像id 镜像id 镜像id # 删除指多个指定的镜像
[root@xizou /]# docker rmi -f $(docker images -aq) # 删除所有的镜像

容器命令

说明:有了镜像才能够创建容器,linux下载一个centos镜像来学习

docker pull centos

docker run 新建容器并启动

docker run [可选参数] image

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

# 测试,启动并进入容器
[root@xizou /]# docker run -it centos /bin/bash
[root@c2fc79886fec /]# ls # 查看容器内的centos,基础版本,很多命令不完善
bin etc lib lost+found mnt proc run srv tmp var
dev home lib64 media opt root sbin sys usr
[root@c2fc79886fec /]# exit # 从容器中退回主机
[root@xizou /]# ls
bin dev home lib64 media opt root sbin sys usr
boot etc lib lost+found mnt proc run srv tmp var

docker ps 列出所有运行的容器

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


[root@xizou /]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES

[root@xizou /]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c2fc79886fec centos "/bin/bash" 5 minutes ago Exited (130) 3 minutes ago competent_gagarin
3c84dcf43e4e feb5d9fea6a5 "/hello" About an hour ago Exited (0) About an hour ago peaceful_pare

退出容器

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

dockers rm 删除容器

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

启动和停止容器的操作

docker start 容器id    # 启动容器
docker restart 容器id # 重启容器
docker stop 容器id # 停止当前正在进行的容器
docker kill 容器id # 强制停止当前容器

常用其他命令

docker run -d 镜像名 后台启动容器

# 测试
[root@xizou /]# docker run -d centos
c2b6244be6c43e1bd6f1e54c1cc7b5b6d0f8c5183c335bf40befafaa4319179c

# 问题:输入docker ps, 发现刚刚后台运行的容器停止了

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

docker logs 查看日志

# 命令
docker logs -tf --tail number 容器id

[root@xizou /]# docker logs -tf --tail 10 d839 # 容器没有日志

# 自己编写一个Shell脚本:每隔1秒打印一个xizou
"while true;do echo xizou;sleep 1;done"

[root@xizou /]# docker run -d centos /bin/sh -c "while true;do echo xizou;sleep 1;done"
817124ceef29bb3d5a06e6c713de0266d83cd46bd2acdbd49c98c5009559f5cc

[root@xizou /]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
817124ceef29 centos "/bin/sh -c 'while t…" 12 minutes ago Up 12 minutes amazing_panini

# 显示日志
-tf # 显示日志
--tail number # 要显示日志条数

[root@xizou /]# docker logs -tf --tail 10 817124ceef29
2022-10-29T06:33:43.399390864Z xizou
2022-10-29T06:33:44.401304775Z xizou
2022-10-29T06:33:45.403554366Z xizou
2022-10-29T06:33:46.405484682Z xizou
2022-10-29T06:33:47.407427195Z xizou
2022-10-29T06:33:48.409551746Z xizou
2022-10-29T06:33:49.411679644Z xizou
2022-10-29T06:33:50.413887957Z xizou
2022-10-29T06:33:51.415868562Z xizou
2022-10-29T06:33:52.417886027Z xizou

docker top 容器id 查看容器中的进程

# 测试
[root@xizou /]# docker top 817124ceef29
UID PID PPID C STIME TTY TIME CMD
root 16181 16163 0 14:18 ? 00:00:00 /bin/sh -c while true;do echo xizou;sleep 1;done
root 17492 16181 0 14:38 ? 00:00:00 /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 1

docker inspect 容器id 查看容器的元数据

# 测试
[root@xizou /]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
817124ceef29 centos "/bin/sh -c 'while t…" 22 minutes ago Up 22 minutes amazing_panini
[root@xizou /]# docker inspect 817124ceef29
[
{
"Id": "817124ceef29bb3d5a06e6c713de0266d83cd46bd2acdbd49c98c5009559f5cc",
"Created": "2022-10-29T06:18:50.373286723Z",
"Path": "/bin/sh",
"Args": [
"-c",
"while true;do echo xizou;sleep 1;done"
],
"State": {
"Status": "running",
"Running": true,
"Paused": false,
"Restarting": false,
"OOMKilled": false,
"Dead": false,
"Pid": 16181,
"ExitCode": 0,
"Error": "",
"StartedAt": "2022-10-29T06:18:50.580743276Z",
"FinishedAt": "0001-01-01T00:00:00Z"
},
"Image": "sha256:5d0da3dc976460b72c77d94c8a1ad043720b0416bfc16c52c45d4847e53fadb6",
"ResolvConfPath": "/var/lib/docker/containers/817124ceef29bb3d5a06e6c713de0266d83cd46bd2acdbd49c98c5009559f5cc/resolv.conf",
"HostnamePath": "/var/lib/docker/containers/817124ceef29bb3d5a06e6c713de0266d83cd46bd2acdbd49c98c5009559f5cc/hostname",
"HostsPath": "/var/lib/docker/containers/817124ceef29bb3d5a06e6c713de0266d83cd46bd2acdbd49c98c5009559f5cc/hosts",
"LogPath": "/var/lib/docker/containers/817124ceef29bb3d5a06e6c713de0266d83cd46bd2acdbd49c98c5009559f5cc/817124ceef29bb3d5a06e6c713de0266d83cd46bd2acdbd49c98c5009559f5cc-json.log",
"Name": "/amazing_panini",
"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/7956a7380425fad866c0faca3fbc9c1f5cd3612322621295eb37dbedd3fd9501-init/diff:/var/lib/docker/overlay2/01b2cb186859ddce9e097143c46cc783da485186a234c8ef6c0827b83b7c389a/diff",
"MergedDir": "/var/lib/docker/overlay2/7956a7380425fad866c0faca3fbc9c1f5cd3612322621295eb37dbedd3fd9501/merged",
"UpperDir": "/var/lib/docker/overlay2/7956a7380425fad866c0faca3fbc9c1f5cd3612322621295eb37dbedd3fd9501/diff",
"WorkDir": "/var/lib/docker/overlay2/7956a7380425fad866c0faca3fbc9c1f5cd3612322621295eb37dbedd3fd9501/work"
},
"Name": "overlay2"
},
"Mounts": [],
"Config": {
"Hostname": "817124ceef29",
"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 xizou;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": "06aa425cd028f11073bf21ac726cd4490fa5eaee627aa9fadc7aedea8ca2644e",
"HairpinMode": false,
"LinkLocalIPv6Address": "",
"LinkLocalIPv6PrefixLen": 0,
"Ports": {},
"SandboxKey": "/var/run/docker/netns/06aa425cd028",
"SecondaryIPAddresses": null,
"SecondaryIPv6Addresses": null,
"EndpointID": "6add7586334f9a3e87d60eb62da7145029d5977a07c61cf63ba409b7407e060d",
"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": "8f02c5589dd1b4b73a11b84188936b90056ca5a1d18676ffb55935132312468f",
"EndpointID": "6add7586334f9a3e87d60eb62da7145029d5977a07c61cf63ba409b7407e060d",
"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 # 进入正在运行的容器

# 测试
[root@xizou /]# docker exec -it 817124ceef29 /bin/bash
[root@817124ceef29 /]# ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 06:18 ? 00:00:00 /bin/sh -c while true;do echo xi
root 1859 0 0 06:49 pts/0 00:00:00 /bin/bash
root 1916 1 0 06:50 ? 00:00:00 /usr/bin/coreutils --coreutils-p
root 1917 1859 0 06:50 pts/0 00:00:00 ps -ef

# 命令2
docker attach 容器id # 进入正在运行的容器

# 测试
[root@xizou /]# docker attach 817124ceef29
xizou
xizou
xizou
xizou

# 如果是死循环导致停不掉容器,新开一个连接后执行 docker stop 容器id

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

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

# 测试
[root@xizou /]# docker ps -aq | xargs docker rm -f
817124ceef29
[root@xizou /]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
# 进入到容器内(重新创建一个容器,或者使用docker attach)
[root@xizou /]# docker run -it centos /bin/bash

# 在容器内创建一个文件
[root@736731cb9072 /]# cd /home
[root@736731cb9072 home]# ls
[root@736731cb9072 home]# touch test.py
[root@736731cb9072 home]# exit
exit
[root@xizou /]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
[root@xizou /]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
736731cb9072 centos "/bin/bash" About a minute ago Exited (0) 7 seconds ago recursing_chatelet

# 将文件拷贝到主机上
[root@xizou /]# docker cp 736731cb9072:/home/test.py /home
[root@xizou /]# cd /home
[root@xizou home]# ls
test.py

# 拷贝是一个手动过程,未来我们使用 -v 卷的技术可以实现自动同步/home目录

小结

Docker命令小结

[root@xizou /]# docker --help
# 解释指令
attach Attach to a running container # 在当前shell下attach连接指定运行的容器
build Build an image from a Dockerfile # 通过Dockerifle定制镜像
commit Create a new image from a container changes # 提交当前容器为新的镜像
cp Copy files/folders from the container filesystem to the host path # 从容器中拷贝指定文件或目录到宿主机中
create Create a new container # 创建一个新的容器,同run,但不启动容器
diff Inspect changes on a container's filesystem # 查看docker容器变化
events Get real time events from the server # 从docker服务获取容器实时事件
exec Run a command in an existing container # 在已存在的容器上运行命令
export Stream the contents of a container as a star archive # 导出容器的内容流作为一个tar归档文件[对应import]
history Show the history of an image # 展示一个镜像形成历史
images List images # 列出系统当前镜像
import Create a new filesystem image from the contents of a barball # 从tar包中的内容创建一个新的文件系统映像[对应export]
info Display system-wide information # 显示系统相关信息
inspect Return low-level information on a container # 查看容器详细信息
kill Kill a running 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源服务器退出
logs Fetch the logs of a container # 输出当前容器日志信息
port Lookup the public-facing port with is NAT-ed to PRIVATE_PORT # 查看映像端口对应的容器内部源端口
pause Pause all processes within a container # 暂停容器
ps List container # 列出容器列表
pull Pull an image or a repository from a registry # 从docker镜像源拉取指定镜像或库镜像
push Push an image or a repository to a registry # 推送指定镜像或库镜像到docker源服务器
rename Rename a container # 重命名一个容器
restart Restart one or more containers # 重启一个或多个运行的容器
rm Remove one or more containers # 移除一个或多个容器
rmi Remove one or more images # 移除一个或多个镜像
run Run a command in a new container # 创建一个新的容器并运行一个命令
save Save one or more images to a tar archive (streamed to STDOUT by default) # 保存一个镜像为一个tar包[对应load]
search Search the Docker Hub for images # 在docker hub中搜索镜像
start Start one or more stopped containers # 启动容器
stats Display a live stream of container(s) resource usage statistics # 展示活动的容器资源使用统计
stop Stop one or more running containers # 停止容器
tag Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE # 给源中镜像打标签
top Display the running processes of a container # 查看容器中运行的进程信息
unpause Unpause all processes within one or more containers # 取消暂停容器
update Update configuration of one or more containers # 更新一个或多个容器配置
version Show the Docker version information # 查看docker版本号
wait Block until one or more containers stop, then print their exit codes # 截取容器停止时的退出状态值

作业练习

部署Nginx

扩展:Nginx是一个高性能的Web服务器,整体功能十分强大,不单单可以用来做Web服务器,还可以用来做反向代理、负载均衡、域名重定向、动静分离、缓存、邮件代理、微服务网关等。

# 1.搜索nginx镜像文件, 建议去docker hub网站搜索,可以看到详细信息
[root@xizou /]# docker search nginx
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
nginx Official build of Nginx. 17590 [OK]
linuxserver/nginx An Nginx container, brought to you by LinuxS… 179
bitnami/nginx Bitnami nginx Docker Image 141 [OK]
ubuntu/nginx Nginx, a high-performance reverse proxy & we… 64
bitnami/nginx-ingress-controller Bitnami Docker Image for NGINX Ingress Contr… 20 [OK]

# 2.拉取nginx镜像到主机
[root@xizou /]# 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@xizou /]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx latest 605c77e624dd 10 months ago 141MB
centos latest 5d0da3dc9764 13 months ago 231MB

# 3.启动 后台启动,以nginx01命名容器,容器内部80端口映射到主机3344端口,使用nginx镜像文件
[root@xizou /]# docker run -d --name nginx01 -p 3344:80 nginx
6bbf807ce91f70a496f31850538b3f77076841195330575288e32efd225b56b0

[root@xizou /]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
6bbf807ce91f nginx "/docker-entrypoint.…" About a minute ago Up About a minute 0.0.0.0:3344->80/tcp, :::3344->80/tcp nginx01

# 4.本机自测
[root@xizou /]# 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>

# 5.远程测试
打开浏览器,输入120.77.233.13:3344测试,(注:需要配置服务器的安全组策略,放行3344端口)会看到nginx欢迎界面。

# 6.进入容器
[root@xizou /]# docker exec -it nginx01 /bin/bash
root@6bbf807ce91f:/# whereis nginx
nginx: /usr/sbin/nginx /usr/lib/nginx /etc/nginx /usr/share/nginx
root@6bbf807ce91f:/# cd /etc/nginx
root@6bbf807ce91f:/etc/nginx# ls
conf.d mime.types nginx.conf uwsgi_params
fastcgi_params modules scgi_params
root@6bbf807ce91f:/etc/nginx# exit
[root@xizou /]# docker stop nginx01

端口暴露的概念

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

部署tomcat

扩展:Tomcat是一款Apache下面的开源的Servlet容器,实现了对Servlet和JSP规范的支持。另外 Tomcat本身内含了一个 HTTP 服务器,所以也可以被当作一个 Web 服务器来使用。但是Tomcat作为一个Web服务器,它对静态资源的处理能力要比Apache或者Nginx这类的Web服务器差很多,所以我们经常将Apache和Tomcat(或者是Nginx和Tomcat)组合使用,Apache来充当Web服务器处理静态资源的请求,Tomcat充当Servlet容器来处理动态请求。

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

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

# 1.下载
[root@xizou /]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx latest 605c77e624dd 10 months ago 141MB
centos latest 5d0da3dc9764 13 months ago 231MB

[root@xizou /]# docker pull tomcat
Using default tag: latest
latest: Pulling from library/tomcat
0e29546d541c: Pull complete
9b829c73b52b: Pull complete
cb5b7ae36172: Pull complete
6494e4811622: Pull complete
668f6fcc5fa5: Pull complete
dc120c3e0290: Pull complete
8f7c0eebb7b1: Pull complete
77b694f83996: Pull complete
0f611256ec3a: Pull complete
4f25def12f23: Pull complete
Digest: sha256:9dee185c3b161cdfede1f5e35e8b56ebc9de88ed3a79526939701f3537a52324
Status: Downloaded newer image for tomcat:latest
docker.io/library/tomcat:latest

[root@xizou /]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx latest 605c77e624dd 10 months ago 141MB
tomcat latest fb5657adc892 10 months ago 680MB
centos latest 5d0da3dc9764 13 months ago 231MB

# 2.启动运行
[root@xizou /]# docker run -d -p 3355:8080 --name tomcat01 tomcat
4f66acd6a158a84bfc0793e9b1c72e9a8a4f7439b2bcf3ea70e330a2dbc2afde

# 3.测试访问没有问题,但是会有404错误
[root@xizou /]# curl localhost:3355
<!doctype html><html lang="en"><head><title>HTTP Status 404 – Not Found</title><style type="text/css">body {font-family:Tahoma,Arial,sans-serif;} h1, h2, h3, b {color:white;background-color:#525D76;} h1 {font-size:22px;} h2 {font-size:16px;} h3 {font-size:14px;} p {font-size:12px;} a {color:black;} .line {height:1px;background-color:#525D76;border:none;}</style></head><body><h1>HTTP Status 404 – Not Found</h1><hr class="line" /><p><b>Type</b> Status Report</p><p><b>Description</b> The origin server did not find a current representation for the target resource or is not willing to disclose that one exists.</p><hr class="line" /><h3>Apache Tomcat/10.0.14</h3></body></html>

# 4.进入容器
[root@xizou /]# docker exec -it tomcat01 /bin/bash
root@4f66acd6a158:/usr/local/tomcat# ll
bash: ll: command not found

# 发现问题:1) linux命令变少了,2) 没有webapps,因为默认是最小的镜像,所有不必要的都剔除了,保证了最小可运行的环境。
# 解决方法:将webapps.dist所有文件拷贝到 webapps即可
# 如果访问仍然失败,记得进入阿里云配置设置安全组策略,开放3355端口访问
root@4f66acd6a158:/usr/local/tomcat# ls
BUILDING.txt NOTICE RUNNING.txt lib temp work
CONTRIBUTING.md README.md bin logs webapps
LICENSE RELEASE-NOTES conf native-jni-lib webapps.dist
root@4f66acd6a158:/usr/local/tomcat# cd webapps.dist/
root@4f66acd6a158:/usr/local/tomcat/webapps.dist# ls
ROOT docs examples host-manager manager
root@4f66acd6a158:/usr/local/tomcat/webapps.dist# cd ..
root@4f66acd6a158:/usr/local/tomcat# cp -r webapps.dist/* webapps
root@4f66acd6a158:/usr/local/tomcat# cd webapps
root@4f66acd6a158:/usr/local/tomcat/webapps# ls
ROOT docs examples host-manager manager

思考问题:每次部署项目,都需要进入容器内部,十分的麻烦,如果在容器外部提供一个映射路径,webapps,在容器外部放置项目,就自动同步到内部就好了 -v 数据卷技术

部署ElasticSearch + Kibana

扩展:

  • ElasticSearch是一个实时的分布式存储、搜索、分析的引擎,它能很方便的使大量数据具有搜索、分析和探索的能力。
  • Kibana 是为 Elasticsearch设计的开源分析和可视化平台。你可以使用 Kibana 来搜索,查看存储在 Elasticsearch 索引中的数据并与之交互。你可以很容易实现高级的数据分析和可视化,以图表的形式展现出来。
# Elasticsearch 暴露的端口很多、十分的耗内存、数据一般需要放置到安全目录
# --net somenetwork 网络配置

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

# 启动之后发现linux服务器非常卡 1核1G,建议1核4G

# 查看docker状态 docker stats
# 测试一下Elasticsearch启动成功了

# 关闭后,给Elasticsearch增加内存限制,修改配置文件 -e 环境配置修改
docker run -d --name elasticsearch02 -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -e ES_JAVA_OPTS="-Xms64m -Xmx256m" elasticsearch:8.4.3

# 查看stats
[root@xizou ~]# docker stats
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
e66569515371 elasticsearch02 0.16% 79.62MiB / 941.5MiB 8.46% 586B / 0B 78.4MB / 0B 15
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
e66569515371 elasticsearch02 99.94% 83.38MiB / 941.5MiB 8.86% 586B / 0B 78.9MB / 0B 15
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
e66569515371 elasticsearch02 99.94% 83.38MiB / 941.5MiB 8.86% 586B / 0B 78.9MB / 0B 15
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
e66569515371 elasticsearch02 99.94% 83.38MiB / 941.5MiB 8.86% 586B / 0B 78.9MB / 0B 15

使用Kibana访问ES

使用Kibana访问ES

可视化

  • portainer
  • Rancher (CI/CD)
  • Openshift

什么是portainer

portainer是Docker的图形化管理工具,提供状态显示面板、应用模板快速部署、容器镜像网络数据卷的基本操作(包括上传下载镜像,创建容器等操作)、事件日志显示、容器控制台操作、Swarm集群和服务等集中管理和操作、登录用户管理和控制等功能。功能十分全面,基本能满足中小型单位对容器管理的全部需求。

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

# 网站访问测试(如果访问失败,记得进入阿里云配置设置安全组策略,开放8088端口访问)
http://120.77.223.13:8088/

# 需要等待一段时间待界面加载完毕

使用教程 https://www.cnblogs.com/JerryMouseLi/p/15571897.html

Portainer操作面板

Docker镜像

镜像是什么

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

所有的应用,直接打包成docker镜像,可以在docker中运行起来。

如何获得镜像:

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

Docker镜像加载原理

UnionFS(联合文件系统)

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

Docker镜像加载

平时我们按照进虚拟机的CentOS都是好几个G、为什么Docker才200M?

[root@xizou /]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
centos latest 5d0da3dc9764 13 months ago 231MB

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

虚拟机是分钟级别的,容器是秒级的。

分层的镜像

可以去下载一个镜像,观察下载的日志输出,可以发现是一层一层在下载。

比如:

# 下载redis
[root@xizou /]# 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

# 查看镜像的元数据
[root@xizou /]# docker image inspect redis:latest
[
{
"Id": "sha256:7614ae9453d1d87e740a2056257a6de7135c84037c367e1fffa92ae922784631",
"RepoTags": [
"redis:latest"
],
"RepoDigests": [
"redis@sha256:db485f2e245b5b3329fdc7eff4eb00f913e09d8feb9ca720788059fdc2ed8339"
],
"Parent": "",
"Comment": "",
"Created": "2021-12-21T12:42:49.755107412Z",
"Container": "13d25f53410417c5220c8dfe8bd49f06abdbcd69faa62a9b877de02464bb04a3",
"ContainerConfig": {
"Hostname": "13d25f534104",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"ExposedPorts": {
"6379/tcp": {}
},
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"GOSU_VERSION=1.12",
"REDIS_VERSION=6.2.6",
"REDIS_DOWNLOAD_URL=http://download.redis.io/releases/redis-6.2.6.tar.gz",
"REDIS_DOWNLOAD_SHA=5b2b8b7a50111ef395bf1c1d5be11e6e167ac018125055daa8b5c2317ae131ab"
],
"Cmd": [
"/bin/sh",
"-c",
"#(nop) ",
"CMD [\"redis-server\"]"
],
"Image": "sha256:e093f59d716c95cfce82c676f099b960cc700432ab531388fcedf79932fc81ec",
"Volumes": {
"/data": {}
},
"WorkingDir": "/data",
"Entrypoint": [
"docker-entrypoint.sh"
],
"OnBuild": null,
"Labels": {}
},
"DockerVersion": "20.10.7",
"Author": "",
"Config": {
"Hostname": "",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"ExposedPorts": {
"6379/tcp": {}
},
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"GOSU_VERSION=1.12",
"REDIS_VERSION=6.2.6",
"REDIS_DOWNLOAD_URL=http://download.redis.io/releases/redis-6.2.6.tar.gz",
"REDIS_DOWNLOAD_SHA=5b2b8b7a50111ef395bf1c1d5be11e6e167ac018125055daa8b5c2317ae131ab"
],
"Cmd": [
"redis-server"
],
"Image": "sha256:e093f59d716c95cfce82c676f099b960cc700432ab531388fcedf79932fc81ec",
"Volumes": {
"/data": {}
},
"WorkingDir": "/data",
"Entrypoint": [
"docker-entrypoint.sh"
],
"OnBuild": null,
"Labels": null
},
"Architecture": "amd64",
"Os": "linux",
"Size": 112691373,
"VirtualSize": 112691373,
"GraphDriver": {
"Data": {
"LowerDir": "/var/lib/docker/overlay2/c972eb0db5fc093c31e9cc9313a6f37ae4c14b41d9d54c44b624efb95eea9348/diff:/var/lib/docker/overlay2/85907f4146eae6f77b7a36316676b53e254038e243a893a9d0b8804fdbfb7499/diff:/var/lib/docker/overlay2/1d2a6a063a36c936689bb84b800821d8a9d154b7cd35f950892b4dafc2286c4d/diff:/var/lib/docker/overlay2/2425fa0f80b5ebeb0675c4938fb4aa32a0073c38d36184989ca39e7bd3aa4556/diff:/var/lib/docker/overlay2/0eb7de4be3f166f2f05d9894a151610ee2952e5cf43175faf1ee2f9e1d0ff737/diff",
"MergedDir": "/var/lib/docker/overlay2/e4a684ba8173df23ed7622b4989678e85ed756b3cc7130ac7f643b1c6cc3db48/merged",
"UpperDir": "/var/lib/docker/overlay2/e4a684ba8173df23ed7622b4989678e85ed756b3cc7130ac7f643b1c6cc3db48/diff",
"WorkDir": "/var/lib/docker/overlay2/e4a684ba8173df23ed7622b4989678e85ed756b3cc7130ac7f643b1c6cc3db48/work"
},
"Name": "overlay2"
},
"RootFS": {
"Type": "layers",
"Layers": [
"sha256:2edcec3590a4ec7f40cf0743c15d78fb39d8326bc029073b41ef9727da6c851f",
"sha256:9b24afeb7c2f21e50a686ead025823cd2c6e9730c013ca77ad5f115c079b57cb",
"sha256:4b8e2801e0f956a4220c32e2c8b0a590e6f9bd2420ec65453685246b82766ea1",
"sha256:529cdb636f61e95ab91a62a51526a84fd7314d6aab0d414040796150b4522372",
"sha256:9975392591f2777d6bf4d9919ad1b2c9afa12f9a9b4d260f45025ec3cc9b18ed",
"sha256:8e5669d8329116b8444b9bbb1663dda568ede12d3dbcce950199b582f6e94952"
]
},
"Metadata": {
"LastTagTime": "0001-01-01T00:00:00Z"
}
}
]

可以发现在RootFS的Layers有分层。

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

理解

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

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

如下图所示,该镜像当前已经包含3个镜像层。

镜像分层01

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

镜像分层02

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

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

镜像分层03

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

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

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

Docker在Windows仅支持Windowsfilter一种存储引擎,该引擎基于NTFS系统之上分层和CoW。

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

镜像统一视图

特点

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

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

镜像层

Commit镜像

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

docker commit -m="提交的描述信息" -a="作者名称" 容器id 目标镜像名:[tag]

实战测试

# 1.启动一个默认的tomcat

# 2.发现这个默认的tomcat是没有webapps应用的,因为官方的镜像默认webapps下面为空

# 3.我们自己拷贝进去基本的文件

# 4.通过commit提交为一个新的镜像
[root@xizou ~]# docker commit -a="xizou" -m="add webapps app" 978a547e22ad tomcat02:1.0
sha256:600af0d3c7c965fe45b24d9019b1289d24dc55241ff19935f390a36621f123ea
[root@xizou ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
tomcat02 1.0 600af0d3c7c9 5 seconds ago 684MB
elasticsearch 8.4.3 ce2b9dc7fe85 3 weeks ago 1.26GB
nginx latest 605c77e624dd 10 months ago 141MB
tomcat latest fb5657adc892 10 months ago 680MB
redis latest 7614ae9453d1 10 months ago 113MB
centos latest 5d0da3dc9764 13 months ago 231MB
portainer/portainer latest 580c0e4e98b0 19 months ago 79.1MB

当想保持容器的状态,可以通过commit来提交,获得一个镜像,就好比虚拟机的快照。

参考文章

本文是笔者通过下列视频教程进行Docker入门学习的记录,有部分修改和补充,转载请注明出处,并附带下面链接。

1.【B站up主-遇见狂神说】