【Docker】Docker 基础

Docker 简介

Docker 理念

Docker 是基于Go语言实现的云开源项目。Docker 的主要目标是“Build, Ship[ and Run Any App,Anywhere",也就是通过对应用组件的封装、分发、部署、运行等生命期的管理,使用户的APP (可以是一个WEB应用或数据库应用等等)及其运行环境能够做到“一次封装,到处运行”。

Linux容器技术的出现就解决了这样一一个问题,而Docker就是在它的基础上发展过来的。将应用运行在Docker容器上面,而Docker容器在任何操作系统上都是一致的,这就实现了跨平台、跨服务器。只需要一次配置好环境,换到别的机器上就可以一键部署好,大大简化了操作

一句话:Docker 是解决了运行环境和配置问题的软件容器,方便做持续集成并有助于整体发布的容器虚拟化技术

之前的虚拟机技术

虚拟机(virtual machine)就是带环境安装的一种解决方案。

它可以在一种操作系统里面运行另一种作系统,比如在Windows系统里面运行Linux系统。应用程序对此毫无感知,因为虚拟机看上去跟真实系统一模一样,而对于底层系统来说,虚拟机就是一个普通文件,不需要了就删掉,对其他部分毫无影响。这类虚拟机完美的运行了另一套系统,能够使应用程序,操作系统和硬件三者之间的逻辑不变。

虚拟机的缺点:

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

容器虚拟化技术

由于前面虛拟机存在这些缺点,Linux 发展出了另一种虚拟化技术: Linux 容器(Linux Containers,缩为LXC)。

Linux 容器不是模拟一个完整的操作系统,而是对进程进行隔离。有了容器,就可以将软件运行所的所有资源打包到一个隔离的容器中。容器与虚拟机不同,不需要捆绑一整套操作系统,只需要软件工作所需的库资源和设置。系统因此而变得高效轻量并保证部署在任何环境中的软件都能始终如一地运行。

比较Docker和传统虚拟化方式的不同之处:

  • 传统虚拟机技术是虚拟出一套硬件后,在其上运行一个完整操作系统,在该系统上再运行所需应用进程。
  • 而容器内的应用进程直接运行于宿主的内核,容器内没有自己的内核,而且也没有进行硬件虚拟。因此容器要比传统虚拟机为轻便。
  • 每个容器之间互相隔离,每个容器有自己的文件系统,容器之间进程不会相互影响,能区分计算资源。

开发/运维(DevOps)

一次构建、随处运行。

更快速的应用交付和部署

​ 传统的应用开发完成后,需要提供一堆安装程序和配置说明文档,安装部署后需根据配置文档进行繁杂的配置才能正常运行。Docker化之后只需要交付少量容器镜像文件,在正式生产环境加载镜像并运行即可,应用安装配置在镜像里已经内置好,大大节省部署配置和测试验证时间。

更便捷的升级和扩缩容

随着微服务架构和Docker的发展,大量的应用会通过微服务方式架构,应用的开发构建将变成搭乐高积木一样,每个Docker容器将变成一块“积木”,应用的升级将变得非常容易。当现有的容器不足以支撑业务处理时,可通过镜像运行新的容器进行快速扩容,使应用系统的扩容从原先的天级变成分钟级甚至秒级。

更简单的系统运维

应用容器化运行后,生产环境运行的应用可与开发、测试环境的应用高度–致,容器会将应用程序相关的环境和状态完全封装起来,不会因为底层基础架构和操作系统的不一致性给应用带来影响,产生新的BUG。当出现程序异常时,也可以通过测试环境的相同容器进行快速定位和修复。

更高效的计算资源利用

Docker是内核级虚拟化,其不像传统的虚拟化技术一样 需要额外的Hypervisor支持,所以在一台物理机上可以运行很多个容器实例,可大大提升物理服务器的CPU和内存的利用率。

Docker 的基本组成

Docker架构图:

镜像(image)

Docker镜像(lmage)就是一个只读的模板。镜像可以用来创建Docker容器,一个镜像可以创建很多容器

通过 docker run imageName/imageID 命令可以创建并运行某一个镜像的容器实例(可以创建多个容器实例)。

容器(container)

Docker利用容器(Container)独立运行的一个或一组应用。容器是用镜像创建的运行实例。它可以被启动、开始、停止、删除。每个容器都是相互隔离的、保证安全的平台。

可以把容器看做是一个简易版的Linux环境(包括root用户权限、进程空间、用户空间和网络空间等)和运行在其中的应用程序。容器的定义和镜像几乎一模一样,也是一堆层的统一视角, 唯一区别在于容器的最上面那一层是可读可写的。

通过 docker commit containerID imageName:tag 命令可以创建出某个容器实例对应的镜像文件,从而将自己自定义的环境进行打包发布。

仓库(repository)

仓库(Repository)是集中存放镜像文件的场所。仓库(Repository)和仓库注册服务器(Registry) 是有区别的。仓库注册服务器上往往存放着多个仓库,每个仓库中又包含了多镜像,每个镜像有不同的标签(tag) 。

仓库分为公开仓库(Public) 和私有仓库(Private) 两种形式。最大的公开仓库是Docker Hub(ttps://hub. docker.com/)。存放了数量庞大的镜像供用户下载。国内的公开仓库包括阿里云、网易云等

总结

需要正确的理解仓储/镜像/容器这几个概念:

Docker本身是一个容器运行载体或称之为管理引擎。我们把应用程序和配置依赖打包好形成一个可交付的运行环境,这个打包好的运行环境就似乎image镜像文件。只有通过这个镜像文件才能生成Docker容器。image文件可以看作是容器的模板。Docker根据image文件生成容器的实例。同一个image文件,可以生成多个同时运行的容器实例。

一个容器运行一种服务,当我们需要的时候,就可以通过Docker客户端创建一个对应的运行实例,也就是我们的容器。至于仓储,就是放了一堆镜像的地方,我们可以把镜像发布到仓储中,需要的时候从仓储中拉下来就可以了。

Docker 底层原理

Docker 是怎样工作的

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

为什么 Docker 比 VM 快

Docker有着比虚拟机更少的抽象层。由于Docker不需要Hypervisor实现硬件资源虚拟化,运行在Docker容器上的程序直接使用的都是实际物理机的硬件资源。因此在CPU、内存利用率上Docker将会在效率上有明显优势。

Docker利用的是宿主机的内核,而不需要Guest OS*。因此,当新建一个容器时,Docker不需要和虚拟机一样重新加载一个操作系统内核仍而避免引导、加载操作系统内核返个比较费时费资源的过程,当新建一个虚拟机时,虚拟机软件需要加载GuestOS,返个新建过程是分钟级别的。而Docker由于直接利用宿主机的操作系统,则省略了返个过程,因此新建一个Docker容器只需要几秒钟。

img

Docker 安装

Docker官网: https://www.docker.com/; Docker中文网站: https://www.docker-cn.com/; Docker Hub官网:https://hub.docker.com/

  1. CentOS 7 安装 Docker:
1
yum install -y docker
  1. 开启 Docker 服务:
1
systemctl start docker.service
  1. 查看安装结果:
1
docker version
  1. 设置开机启动:
1
systemctl enable docker.service
  1. 配置 docker 镜像下载加速。编辑配置⽂件:
1
vim /etc/docker/daemon.json

在其中加入加速镜像源地址即可(https://cr.console.aliyun.com/cn-hangzhou/instances/mirrors):

1
2
3
{
"registry-mirrors": ["https://gc2odbl5.mirror.aliyuncs.com"]
}

加完加速地址后,重新加载配置⽂件,重启docker 服务即可:

1
2
systemctl daemon-reload
systemctl restart docker.service

Docker 常用命令

基础命令

1
2
3
4
docker version           # 查看docker的版本信息
docker info # 查看docker的系统信息,包括镜像和容器的数量
docker xxx --help # 帮助命令(可查看可选的参数)
docker COMMAND --help

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

镜像命令

  1. docker images 查看本地主机的所有镜像:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
[root@iZwz99sm8v95sckz8bd2c4Z ~]$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest bf756fb1ae65 11 months ago 13.3kB

# 解释:
1.REPOSITORY 镜像的仓库源
2.TAG 镜像的标签
3.IMAGE ID 镜像的id
4.CREATED 镜像的创建时间
5.SIZE 镜像的大小

# 可选参数
-a/--all 列出所有镜像
-q/--quiet 只显示镜像的id
  1. docker search 搜索DockerHub仓库中的镜像:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
[root@iZwz99sm8v95sckz8bd2c4Z ~]$ docker search mysql
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
mysql MySQL is a widely used, open-source relation… 10308 [OK]
mariadb MariaDB is a community-developed fork of MyS… 3819 [OK]
mysql/mysql-server Optimized MySQL Server Docker images. Create… 754 [OK]
percona Percona Server is a fork of the MySQL relati… 517 [OK]
centos/mysql-57-centos7 MySQL 5.7 SQL database server 86
mysql/mysql-cluster Experimental MySQL Cluster Docker images. Cr… 79
centurylink/mysql Image containing mysql. Optimized to be link… 60 [OK]

# 可选参数
Search the Docker Hub for images

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 Do not truncate output

# 搜索收藏数大于3000的镜像
[root@iZwz99sm8v95sckz8bd2c4Z ~]$ docker search mysql --filter=STARS=3000
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
mysql MySQL is a widely used, open-source relation… 10308 [OK]
mariadb MariaDB is a community-developed fordockerk of MyS… 3819 [OK]
  1. docker pull 镜像名[:tag] 下载镜像:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
[root@iZwz99sm8v95sckz8bd2c4Z ~]$ docker pull mysql
Using default tag: latest # 如果不写tag默认就是latest
latest: Pulling from library/mysql
6ec7b7d162b2: Pull complete # 分层下载,docker image的核心-联合文件系统
fedd960d3481: Pull complete
7ab947313861: Pull complete
64f92f19e638: Pull complete
3e80b17bff96: Pull complete
014e976799f9: Pull complete
59ae84fee1b3: Pull complete
ffe10de703ea: Pull complete
657af6d90c83: Pull complete
98bfb480322c: Pull complete
6aa3859c4789: Pull complete
1ed875d851ef: Pull complete
Digest: sha256:78800e6d3f1b230e35275145e657b82c3fb02a27b2d8e76aac2f5e90c1c30873 #签名
Status: Downloaded newer image for mysql:latest
docker.io/library/mysql:latest # 下载来源的真实地址

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

指定版本下载:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[root@iZwz99sm8v95sckz8bd2c4Z ~]$ docker pull mysql:5.7
5.7: Pulling from library/mysql
6ec7b7d162b2: Already exists
fedd960d3481: Already exists
7ab947313861: Already exists
64f92f19e638: Already exists
3e80b17bff96: Already exists
014e976799f9: Already exists
59ae84fee1b3: Already exists
7d1da2a18e2e: Pull complete
301a28b700b9: Pull complete
529dc8dbeaf3: Pull complete
bc9d021dc13f: Pull complete
Digest: sha256:c3a567d3e3ad8b05dfce401ed08f0f6bf3f3b64cc17694979d5f2e5d78e10173
Status: Downloaded newer image for mysql:5.7
docker.io/library/mysql:5.7
  1. docker rmi 删除镜像:
1
2
3
4
5
6
# 1.删除指定的镜像id
[root@iZwz99sm8v95sckz8bd2c4Z ~]$ docker rmi -f 镜像id
# 2.删除多个镜像id
[root@iZwz99sm8v95sckz8bd2c4Z ~]$ docker rmi -f 镜像id 镜像id 镜像id
# 3.删除全部的镜像id
[root@iZwz99sm8v95sckz8bd2c4Z ~]$ docker rmi -f $(docker images -aq)
  1. docker commit 提交容器副本使之称为一个新的镜像:
1
$ docker commit -m="提交的描述信息" -a="作者" 容器ID 要创建的目标镜像名:[标签名]

容器命令

  1. docker run 运行容器:
1
2
3
4
5
6
7
8
9
10
11
12
13
$ docker run [可选参数] image

# 参数说明
--name="名字" 指定容器名字
-d 后台方式运行
-it 使用交互方式运行,进入容器查看内容
-p 指定容器的端口
(
-p ip:主机端口:容器端口 配置主机端口映射到容器端口
-p 主机端口:容器端口
-p 容器端口
)
-P 随机指定端口(大写的P)

以前台方式进入容器,并进行交互:

1
2
3
[root@iZwz99sm8v95sckz8bd2c4Z ~]$ docker run -it centos /bin/bash
[root@bd1b8900c547 /]$ ls
bin dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var
  1. 退出容器:
1
2
3
4
5
# exit 停止并退出容器(后台方式运行则仅退出)
# Ctrl+P+Q 不停止容器退出
[root@bd1b8900c547 /]$ exit
exit
[root@iZwz99sm8v95sckz8bd2c4Z ~]$
  1. docker ps 列出运行过的容器:
1
2
3
4
5
6
7
8
9
10
11
12
$ docker ps  # 列出当前正在运行的容器
-a # 列出所有容器的运行记录
-n=? # 显示最近创建的n个容器
-q # 只显示容器的编号

[root@iZwz99sm8v95sckz8bd2c4Z ~]$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
[root@iZwz99sm8v95sckz8bd2c4Z ~]$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
bca129320bb5 centos "/bin/bash" 4 minutes ago Exited (0) 3 minutes ago optimistic_shtern
bd1b8900c547 centos "/bin/bash" 6 minutes ago Exited (0) 5 minutes ago cool_tesla
cf6adbf1b506 bf756fb1ae65 "/hello" 5 hours ago Exited (0) 5 hours ago optimistic_darwin
  1. docker rm 删除容器:
1
2
3
$ docker rm 容器id                 # 删除指定的容器,不能删除正在运行的容器,强制删除使用 rm -f
$ docker rm -f $(docker ps -aq) # 删除所有的容器
$ docker ps -a -q|xargs docker rm # 删除所有的容器
  1. 启动和停止容器:
1
2
3
4
$ docker start 容器id          # 启动容器
$ docker restart 容器id # 重启容器
$ docker stop 容器id # 停止当前运行的容器
$ docker kill 容器id # 强制停止当前容器
  1. docker run -d xxx 启动守护式容器(在后台运行)

其他常用命令

  1. 日志的查看
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[root@iZwz99sm8v95sckz8bd2c4Z ~]$ docker logs --help

# 常用:
[root@iZwz99sm8v95sckz8bd2c4Z ~]$ docker logs -tf 容器id
[root@iZwz99sm8v95sckz8bd2c4Z ~]$ docker logs --tail number 容器id # num为要显示的日志条数

# docker容器后台运行,必须要有一个前台的进程,否则会自动停止
# 编写shell脚本循环执行,使得centos容器保持运行状态
[root@iZwz99sm8v95sckz8bd2c4Z ~]$ docker run -d centos /bin/sh -c "while true;do echo hi;sleep 5;done"
c703b5b1911ff84d584390263a35707b6024816e1f46542b61918a6327a570dc
[root@iZwz99sm8v95sckz8bd2c4Z ~]$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c703b5b1911f centos "/bin/sh -c 'while t…" 13 seconds ago Up 10 seconds pedantic_banach
[root@iZwz99sm8v95sckz8bd2c4Z ~]$ docker logs -tf --tail 10 c703b5b1911f
2020-12-27T03:34:07.255599560Z hi
2020-12-27T03:34:12.257641517Z hi
2020-12-27T03:34:17.259706294Z hi
  1. 查看容器中的详细信息:
1
2
3
[root@iZwz99sm8v95sckz8bd2c4Z ~]$ docker stats
CONTAINER CPU % MEM USAGE / LIMIY MEM % NET I/O BLOCK I/O PIDS
82e22dd9bb52 0.04% 1.484 MiB / 1.795 GiB 0.08 % 1.45 MiB 1.03 MB 2
  1. 查看容器中进程信息:
1
2
3
4
[root@iZwz99sm8v95sckz8bd2c4Z ~]$ docker top c703b5b1911f
UID PID PPID C STIME TTY TIME CMD
root 11156 11135 0 11:31 ? 00:00:00 /bin/sh -c while true;do echo hi;sleep 5;done
root 11886 11156 0 11:43 ? 00:00:00 /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 5
  1. docker inspect 查看容器的元数据(查看容器内部细节):
1
[root@iZwz99sm8v95sckz8bd2c4Z ~]$ docker inspect 容器id
  1. 进入当前正在运行的容器:

因为通常我们的容器都是使用后台方式来运行的,有时需要进入容器修改配置。

方式一:

1
2
3
4
5
6
7
8
9
[root@iZwz99sm8v95sckz8bd2c4Z ~]$ docker exec -it c703b5b1911f /bin/bash
[root@c703b5b1911f /]$ ls
bin dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var
[root@c703b5b1911f /]$ ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 03:31 ? 00:00:00 /bin/sh -c while true;do echo hi;sleep 5;done
root 279 0 0 03:54 pts/0 00:00:00 /bin/bash
root 315 1 0 03:56 ? 00:00:00 /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 5
root 316 279 0 03:56 pts/0 00:00:00 ps -ef

方式二:

1
[root@iZwz99sm8v95sckz8bd2c4Z ~]$ docker attach c703b5b1911f

区别:

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

docker exec 详细参数介绍:https://www.runoob.com/docker/docker-exec-command.html

  1. docker cp 拷贝容器的文件到主机中:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# docker cp 容器id:容器内路径 目的主机路径

[root@iZwz99sm8v95sckz8bd2c4Z ~]$ docker exec -it c703b5b1911f /bin/bash
[root@c703b5b1911f /]$ cd home
[root@c703b5b1911f home]$ ls
[root@c703b5b1911f home]$ touch test.java
[root@c703b5b1911f home]$ ls
test.java
[root@c703b5b1911f home]$ exit
exit
[root@iZwz99sm8v95sckz8bd2c4Z ~]$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c703b5b1911f centos "/bin/sh -c 'while t…" 35 minutes ago Up 35 minutes pedantic_banach
[root@iZwz99sm8v95sckz8bd2c4Z ~]$ docker cp c703b5b1911f:/home/test.java /home
[root@iZwz99sm8v95sckz8bd2c4Z ~]$ ls /home
hai pan test.java

总结

完整命令示意图:

Docker 镜像

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

UnionFS(联合文件系统)

UnionFS (联合文件系统) : Union文件系统(UnionFS)是一一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修作为一 次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下(unite several directories into a singlevirtualfilesystem)。Union文件系统是Docker镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像)可以制作各种具.体的应用镜像。

特性:一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录

Docker 镜像加载原理

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

botfs(boot file system)主要包含bootloaderkernelbootloader主要是引导加载kernelLinux刚启动时会加载bootfs文件系统,在Docker镜像的最底层是bootfs。这一层与我们典型的Linux/Unix系统是一样的,包含boot加载器和内核。当boot加载完成之后整个内核就都在内存中了,此时内存的使用权己由bootfs转交给内核,此时系统也会卸载bootfs。

rootfs (root file system),bootfs之上。 包含的就是典型Linux系统中的 /dev, /proc, /bin, /etc 等标准目录和文件。rootfs就是各种不同的操作系统发行版,比如UbuntuCentos等等。

image-20211109145554754

平时我们安装的虚拟机的Centos都是好几个G ,为什么Docker这里才要200M?

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

分层的镜像

下载一个镜像时,可以看到是分层下载的:

image-20211109143422083

为什么 Docker 镜像要采用这种分层结构

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

特点:Docker镜像都是只读的,当容器启动时,一个新的可写层被加载到镜像的顶部,这一层通常被称为容器层,容器层之下都叫镜像层

image-20211109144853656

image-20211109144905762

image-20211109144953165

Docker 镜像 Commit 操作

docker commit 提交容器副本使之称为一个新的镜像:

1
$ docker commit -m="提交的描述信息" -a="作者" 容器ID 要创建的目标镜像名:[标签名]

案例:提交 Tomcat 镜像

由于默认的Tomcat镜像的webapps文件夹中没有任何内容,需要从webapps.dist中拷贝文件到webapps文件夹。下面自行制作镜像:就是从webapps.dist中拷贝文件到webapps文件夹下,并提交该镜像作为一个新的镜像。使得该镜像默认的webapps文件夹下就有文件。具体命令如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# 1.复制文件夹
[root@iZwz99sm8v95sckz8bd2c4Z ~]$ docker run -it tomcat /bin/bash
root@2a3bf3eaa2e4:/usr/local/tomcat $ cd webapps
root@2a3bf3eaa2e4:/usr/local/tomcat/webapps $ ls
root@2a3bf3eaa2e4:/usr/local/tomcat/webapps $ cd ../
root@2a3bf3eaa2e4:/usr/local/tomcat $ cp -r webapps.dist/* webapps
root@2a3bf3eaa2e4:/usr/local/tomcat $ cd webapps
root@2a3bf3eaa2e4:/usr/local/tomcat/webapps $ ls
ROOT docs examples host-manager manager
[root@iZwz99sm8v95sckz8bd2c4Z ~]$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2a3bf3eaa2e4 tomcat "/bin/bash" 4 minutes ago Up 4 minutes 8080/tcp competent_torvalds
7789d4505a00 portainer/portainer "/portainer" 24 hours ago Up 24 hours 0.0.0.0:8088->9000/tcp quirky_sinoussi
[root@iZwz99sm8v95sckz8bd2c4Z ~]$ docker exec -it 2a3bf3eaa2e4 /bin/bash
root@2a3bf3eaa2e4:/usr/local/tomcat $ cd webapps
root@2a3bf3eaa2e4:/usr/local/tomcat/webapps $ ls
ROOT docs examples host-manager manager
root@2a3bf3eaa2e4:/usr/local/tomcat/webapps $ cd ../
root@2a3bf3eaa2e4:/usr/local/tomcat $ read escape sequence
[root@iZwz99sm8v95sckz8bd2c4Z ~]$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2a3bf3eaa2e4 tomcat "/bin/bash" 8 minutes ago Up 8 minutes 8080/tcp competent_torvalds
7789d4505a00 portainer/portainer "/portainer" 24 hours ago Up 24 hours 0.0.0.0:8088->9000/tcp quirky_sinoussi

# 2.提交镜像作为一个新的镜像
[root@iZwz99sm8v95sckz8bd2c4Z ~]$ docker commit -m="add webapps" -a="Ethan" 2a3bf3eaa2e4 mytomcat:1.0
sha256:f189aac861de51087af5bc88a5f1de02d9574e7ee2d163c647dd7503a2d3982b
[root@iZwz99sm8v95sckz8bd2c4Z ~]$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mytomcat 1.0 f189aac861de 7 seconds ago 653MB
mysql 5.7 f07dfa83b528 6 days ago 448MB
tomcat latest feba8d001e3f 10 days ago 649MB
nginx latest ae2feff98a0c 12 days ago 133MB
centos latest 300e315adb2f 2 weeks ago 209MB
portainer/portainer latest 62771b0b9b09 5 months ago 79.1MB
elasticsearch 7.6.2 f29a1ee41030 9 months ago 791MB

# 3.运行容器
[root@iZwz99sm8v95sckz8bd2c4Z ~]$ docker run -it mytomcat:1.0 /bin/bash
root@1645774d4605:/usr/local/tomcat $ cd webapps
root@1645774d4605:/usr/local/tomcat/webapps $ ls
ROOT docs examples host-manager manager
wz99sm8v95sckz8bd2c4Z ~]$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mytomcat 1.0 f189aac861de 7 seconds ago 653MB
mysql 5.7 f07dfa83b528 6 days ago 448MB
tomcat latest feba8d001e3f 10 days ago 649MB
nginx latest ae2feff98a0c 12 days ago 133MB
centos latest 300e315adb2f 2 weeks ago 209MB
portainer/portainer latest 62771b0b9b09 5 months ago 79.1MB
elasticsearch 7.6.2 f29a1ee41030 9 months ago 791MB

Docker 容器数据卷

Docker的理念:将运用与运行的环境打包形成容器运行。运行可以伴随着容器,但是我们对数据的要求希望是持久化的,容器之间希望有可能共享数据。

Docker容器产生的数据,如果不通过docker commit生成新的镜像,使得数据做为镜像的一部分保存下来,那么当容器删除后,数据自然也就没有了。为了能保存数据在docker中我们使用卷。

有点类似我们Redis里面的rdb和aof文件

卷就是目录或文件,存在于一个或多个容器中,由Docker挂载到容器,但不属于联合文件系统,因此能够绕过Union FileSystem提供一些用于持续存储或共享数据的特性:

卷的设计目的就是数据的持久化,完全独立于容器的生存周期,因此Docker不会在容器被删除时删除其挂载的数据卷。特点:

  • 数据卷可在容器之间共享或重用数据
  • 卷中的更改可以直接生效
  • 数据卷中的更改不会包含在镜像的更新中
  • 数据卷的生命周期一直持续到没有容器使用它为止

容器的持久化:容器间继承 + 共享数据

添加数据卷方式一:命令行

1
2
3
4
$ docker run -it -v /宿主机绝对路径目录:/容器内目录 镜像名

# 设置数据卷权限为只读
$ docker run -it -v /宿主机绝对路径目录:/容器内目录:ro 镜像名

查看数据卷是否挂载成功:

使用数据卷即可实现容器和宿主机之间数据共享。

添加数据卷方式二:DockerFile 添加

在 Dockerfile 文件中使用VOLUME指令来给镜像添加一个或多个数据卷:

注意,该文件中写的路径是在容器中的路径,宿主机上关联的对应路径是随机生成的名称,不包含在该文件中(出于可移植和共享的考虑)。

docker build 后生成镜像:

对应的宿主机中关联的目录需要使用 docker inspect 镜像id 进行查看:

Docker挂载主机目录Docker访问如果出现cannot open directory . Permission denied。解决办法:在挂载目录后多加一个--privileged=true参数即可

数据卷容器

某个容器挂载数据卷,其它容器通过挂载这个(父容器)实现数据共享,挂载数据卷的这个容器,称之为数据卷容器。

即某个容器挂在了数据卷,其他容器使用 --volumes-from 参数继承自该容器,则这些容器都可以共享同一份数据,称这个父容器为数据卷容器。之后即使删除了父容器,之前“继承”出的子容器也仍然能共享那些数据。

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

DockerFile 解析

Dockerfile 是用来构建Docker镜像的构建文件,由一系列命令和参数构成的脚本。

从应用软件的角度来看,Dockerfile、 Docker镜像与Docker容器分别代表软件的三个不同阶段:

  • Dockerfile是软件的原材料
  • Docker镜像是软件的交付品
  • Docker容器则可以认为是软件的运行态

Dockerfile面向开发,Docker镜像成为交付标准,Docker容器则涉及部署与运维,三者缺一不可,合力充当Docker体系的基石。

  • Dockerfile,需要定义一个Dockerfile,Dockerfile定义了进程需要的一切东西。Dockerfile涉及的内容包括执行代码或者是文件、环境变量、依赖包、运行时环境、动态链接库、操作系统的发行版、服务进程和内核进程(当应用进程需要和系统服务和内核进程打交道,这时需要考虑如何设计namespace的权限控制)等等
  • Docker镜像,在用Dockerfile定义文件之后,docker build时会产生一个Docker镜像,当运行Docker镜像时,会真正开始提供服务
  • Docker容器,容器是直接提供服务的

Docker 执行 Dockerfile 的大致流程

  • docker 从基础镜像运行一个容器
  • 执行一条指令并对容器作出修改
  • 执行类似docker commit的操作提交一个新的镜像层
  • docker再基于刚提交的镜像运行一个新容器
  • 执行dockerfile中的下一条指令直到所有指令都执行完成

DockerFile 体系结构(保留字指令)

image-20211109185453109

image-20211109185510613

案例

Base 镜像(scratch)

Docker Hub中 99%的镜像都是通过在base镜像中安装和配置需要的软件构建出来的

自定义镜像 mycentos

  1. 编写Dockerfile文件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
FROM centos
MAINTAINER ZZYY<zzyy167@126.com>

ENV MYPATH /usr/local
WORKDIR $MYPATH

RUN yum -y install vim
RUN yum -y install net-tools

EXPOSE 80

CMD echo $MYPATH
CMD echo "success--------------ok"
CMD /bin/bash
  1. 构建镜像文件:docker build -t 新镜像名字:TAG .

  1. 运行:docker run -it 新镜像名字:TAG

  1. 列出镜像的变更历史:docker history 镜像名

Docker 镜像推送到阿里云

本地镜像发布到阿里云流程:

生成镜像

从配置好环境的容器中打包创建一个新的镜像:

1
docker commit [OPTIONS] 容器ID [REPOSITORY[:TAG]]

将本地镜像推送到阿里云

  1. 登录阿里云开发者平台:https://promotion.aliyun.com/ntms/act/kubernetes.html

  1. 创建阿里云镜像仓库:

  1. 将镜像推送到 registry:
1
2
3
4
5
6
$ sudo docker login --username=white3e registry.cn-shenzhen.aliyuncs.com

$ sudo docker tag [ImageId] registry.cn-shenzhen.aliyuncs.com/ggccqq/mycentos:[镜像版本号]

$ sudo docker push registry.cn-shenzhen.aliyuncs.com/ggccqq/mycentos:[镜像版本号]
其中[ImageId][镜像版本]自己填写

  1. 公有云查询信息:

将阿里云上的镜像下载到本地