Docker简介

Docker 是一个开源的应用容器引擎,基于 Go 语言 并遵从 Apache2.0 协议开源。

Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。

容器是完全使用沙箱机制,相互之间不会有任何接口,更重要的是容器性能开销极低。

Docker 从 17.03 版本之后分为 CE(Community Edition: 社区版) 和 EE(Enterprise Edition: 企业版)

总而言之,Docker所使用的容器技术使得应用程序和对应的配置环境能够统一整合起来并交付给其他环境,避免了需要反复从头配置环境甚至debug的苦恼。

容器与虚拟机

虚拟机同样也是一种可携带环境安装状态实现跨平台的解决方案。虚拟机在云计算中发挥着至关重要的作用,它通过在隔离的实例中运行操作系统模拟物理计算机

当然,虚拟机和容器是两种不同的虚拟化技术,它们在应用部署和资源管理方面有明显的区别。

虚拟机

  1. 虚拟机是基于硬件的虚拟化技术。它通过完全模拟硬件环境来实现虚拟化。
  2. 每个虚拟机运行一个完整的操作系统,包括内核和用户空间。这意味着每个虚拟机都需要占用大量的磁盘空间和内存。
  3. 虚拟机之间相互隔离,每个虚拟机都有自己的操作系统和依赖。
  4. 启动虚拟机需要数分钟,因为它们需要加载整个操作系统。
  5. 虚拟机的资源利用率较低,因为它们运行独立的操作系统。

容器

  1. 容器是应用程序级别的虚拟化技术,不需要模拟整个操作系统环境。
  2. 容器共享主机操作系统内核,因此它们更轻量级。每个容器只包含应用程序和其依赖,而不需要额外的操作系统。
  3. 容器之间相互隔离,但共享同一个操作系统。它们运行在相同的内核上,因此启动速度非常快。
  4. 容器的资源利用率高,因为它们共享主机操作系统。
  5. 容器更易于移植,可以在不同的环境中运行。

虚拟机与容器的对比

总之,虚拟机更适合彻底隔离整个运行环境,例如云服务提供商使用虚拟机隔离不同的用户。而容器更适用于隔离不同的应用,例如前端、后端和数据库。选择虚拟机还是容器取决于具体的使用场景和需求。

Docker架构

Docker 包括三个基本概念:

  • 镜像(Image):Docker 镜像(Image),就相当于是一个 root 文件系统。比如官方镜像 ubuntu:16.04 就包含了完整的一套 Ubuntu16.04 最小系统的 root 文件系统。
  • 容器(Container):镜像(Image)和容器(Container)的关系,就像是面向对象程序设计中的实例一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。
  • 仓库(Repository):仓库可看成一个代码控制中心,用来保存镜像。类似于 Github 仓库,官方也有自己仓库网站: https://hub.docker.com/

安装引擎

Docker Engine 的安装具体可以查看 官方文档:Docker Engine overview | Docker Docs

通过如下命令核实安装情况:

1
2
3
4
5
6
7
sudo systemctl start docker #启动Docker服务

docker version #查看版本(如果没有执行上一行,则只有Client信息)

ps -ef | grep docker #查看运行情况

sudo docker run --rm hello-world #容器生成测试

OpenSUSE Leap 的安装方法详见:Docker - openSUSE Wiki

镜像加速

通过 阿里云的镜像服务(个人版)获取镜像加速器的 URL,并将其添加至配置文件中:

1
2
3
4
5
6
7
8
9
10
sudo mkdir -p /etc/docker 

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

sudo systemctl daemon-reload
sudo systemctl restart docker

可通过命令 docker info 查看是否存在 Registry Mirrors: xxx 项判断是否配置成功。

常用命令

启动与停止

1
2
3
4
5
6
7
sudo systemctl start docker #启动Docker服务
sudo systemctl stop docker #停止Docker服务
sudo systemctl restart docker #重启Docker服务

sudo systemctl enable docker #docker自启动

sudo systemctl status docker #查看Docker状态

镜像相关命令

查看镜像情况

查看本地镜像:docker images [-a列出含历史镜像层的所有镜像] [-q只显示镜像ID]

1
2
3
localhost:~ # docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest feb5d9fea6a5 2 years ago 13.3kB

查看占用空间情况:docker system df

虚悬镜像,待更

1
docker image ls -f dangling=true

搜索与拉取

搜索相关镜像:docker search <image_name> [--limit n 仅显示前n条]

1
2
3
4
5
6
localhost:~ # docker search ubuntu --limit 4
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
ubuntu Ubuntu is a Debian-based Linux operating sys… 16923 [OK]
websphere-liberty WebSphere Liberty multi-architecture images … 298 [OK]
open-liberty Open Liberty multi-architecture images based… 64 [OK]
ubuntu-debootstrap DEPRECATED; use "ubuntu" instead 52 [OK]

拉取对应版本的镜像:docker pull <image_name>[:tag指定版本号]

1
2
3
4
5
6
7
localhost:~ # docker pull ubuntu
Using default tag: latest
latest: Pulling from library/ubuntu
7b1a6ab2e44d: Pull complete
Digest: sha256:626ffe58f6e7566e00254b638eb7e0f3b11d4da9675088f4781a50ae288f3322
Status: Downloaded newer image for ubuntu:latest
docker.io/library/ubuntu:latest

镜像的删除

删除指定镜像:docker rmi <image_name/image_id> [-f强制删除]

1
2
3
docker rmi a b c #同时删除镜像a、镜像b和镜像c
docker rmi -f $(docker images -qa) #强制删除全部镜像
docker images prune #删除所有的虚悬镜像

容器相关命令

查看当前正在运行的容器:

1
docker ps [-a列出历史运行过的所有容器] [-n x, 只显示最近x个] [-p只显示容器ID]`

容器的运行与重进

1
docker run <image_name>[:tag] [--name对容器进行自定义命名]

该命令将根据镜像生成(新的)容器并运行之,此外特别注意的是其他的可用参数有:

  • -it:前台交互终端运行(是 -i 前台和 -t 终端的结合)
  • -d:后台静默运行
  • -P:随机端口映射
  • -p:指定端口映射 【常用:-p HostPort:ContainerPort

例如进入 Ubuntu 容器:

1
2
localhost:~ # docker run -it ubuntu
root@07bbb724ad5d:/#

在容器中通过命令 exit 可退出该容器(容器会停止运行);
而通过快捷键Ctrl+P+Q 退出交互式终端状态(容器依然后台运行)。

要想重新进入正在运行的容器时,可通过如下命令实现:

1
2
3
docker exec [-it / -d] <container_id> bash
# or
docker attech <container_id>

值得注意的是,如果使用 exec 重进容器,在容器内使用 exit 退出时,容器不会停止会继续在后台运行。

停止、再启动和删除

在容器中(交互方式)通过命令 exit 可退出该容器,并且容器会停止运行
在容器外(静默方式)通过命令 docker stop <container_id> 停止正在运行的容器;将 stop 替换为 kill 则是强制停止

通过 docker ps -a 会列出所有曾经运行过的容器(即使已经停止了):

1
2
3
4
localhost:~ # docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
07bbb724ad5d ubuntu "bash" 16 minutes ago Exited (0) 5 seconds ago confident_chaum

可以在 STATUS 中看出某容器是否仍在运行:Up 是在运行,Exited.. 则是已停止但存在过。

接下来,我们可通过命令将该容器再次激活

1
docker start <container_id> [<container_name>]

示例:

1
2
3
4
5
6
7
8
9
localhost:~ # docker start confident_chaum
confident_chaum

localhost:~ # docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
07bbb724ad5d ubuntu "bash" 20 minutes ago Up 7 seconds confident_chaum

localhost:~ # docker exec -it confident_chaum bash
root@07bbb724ad5d:/#

然后是删除容器

1
docker rm <container_id>

注意,此处是 rm 代表删除的是容器,如果是 rmi 则是删除镜像。
当容器正在运行时不予删除,需要先停止之再删除,或者使用 -f 强制删除;
此外,删除后通过 docker ps -a 在历史中也再也找不到该容器了,同理也无法再 start 重新启动了。

示例如下:

1
2
3
4
5
6
7
8
localhost:~ # docker rm confident_chaum
Error response from daemon: You cannot remove a running container 07bbb724ad5d2661d3505826d952ca418748b09a32a8aa4257d05b4da146d006. Stop the container before attempting removal or force remove

localhost:~ # docker rm -f confident_chaum
confident_chaum

localhost:~ # docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES

容器的日志与进程

docker logs <container_id>:查看正在运行的容器后台打印的日志
docker top <container_id>:查看正在运行的容器内的进程运行情况

容器与主机文件传输

docker cp <container_id>:<container_file_path> <host_path> 将容器内的文件复制到主机指定目录下。

示例:

1
2
3
4
localhost:~ # docker cp ccd87ecf82c1:/home/myfile.txt /home/data
localhost:~ # cd /home/data
localhost:/home # ls
hello.c myfile.txt

容器的导入与导出

docker export <container_id> > filename.tar

cat filename.tar | docker import - user/myimagename:mytag

镜像创建与仓库管理

Docker 镜像是分层的,最底层通常是复制主机的 kernel bootfs 进行引导,然后往上堆叠不同操作系统的最精简 rootfs。再往上可以继续堆叠不同的环境和资源包。

镜像内容是只读的,按镜像生成的容器则是可读写的。为了在原有镜像上进行修改并生成新的镜像以便复用,我们需要对进行修改的容器进行反射以构建出新的镜像。

Commit

1
docker commit -m="description" -a="author" <container_id> <myImageName>:<myTag>

以 Docker 的 Ubuntu 镜像为例,其中不含有 vim 命令,我们为其安装上之后再将其打包成含有 vim 命令的新的 Ubuntu 镜像。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
localhost:/home # docker run -it ubuntu

root@875ab4a677aa:/# vim abc.txt
bash: vim: command not found

root@875ab4a677aa:/# apt-get update
root@875ab4a677aa:/# apt-get -y install vim

root@875ab4a677aa:/# vim abc.txt
root@875ab4a677aa:/# cat abc.txt
this is my new text file

# 回到主机

localhost:/home # docker commit -m="add vim cmd" -a="slie" 875ab4a677aa my_ubuntu:0.0.1
sha256:dffea2cd3b43cc2040ada733177889f49b30b55ea646b075ed5fd3fe1a74e3e1

localhost:/home # docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
my_ubuntu 0.0.1 dffea2cd3b43 48 seconds ago 190MB
ubuntu latest ba6acccedd29 2 years ago 72.8MB
hello-world latest feb5d9fea6a5 2 years ago 13.3kB

阿里云推送与拉取

在阿里云中创建【命名空间】和【仓库】后,

待更

搭建私有仓库

除了阿里云、DockerHub等第三方公网的Docker仓库以外,Docker自然也运行搭建自己的私有仓库,供可信任的人员访问。这个搭建私有Registry的环境甚至也被Docker官方做成了镜像供开发者、运维快速复现。

容器数据卷

容器数据卷实现了容器内指定的文件夹主机指定文件夹的“映射共享”。使得在容器外/主机上可以对该文件夹加入删除或是修改文件,这些操作会同步到容器对应的文件夹内。

其实就是一个持久性挂载的作用——即使容器被停止或删除,主机上该文件夹的内容不会被删除。

如果不使用容器数据卷方法,临时进行简单的文件传输,则可使用 cp 命令。

使用容器数据卷的命令如下,它执行在通过镜像运行一个容器之前,利用 -v 实现:

1
docker run [-it/-d] -v /HostPath:/ContainerPath IMAGE

通常,为了防止权限bug,还需要添加参数 --privileged=true

读写权限

在编写映射时,还可以对容器进行读写权限的限制

1
docker run -it --privileged=true -v /home/slie:/tmp/shared_floder:ro --name="u1" ubuntu

上述命令使得主机下的 /home/slie 文件夹与名为 u1 的一个Ubuntu容器内的 /tmp/shared_floder 文件夹实现共享,并且主机自由可读写,但是容器只能读不能写,即 Read Only ro

容器卷的继承

当我们想让 容器b 继承 容器a 的映射方式时,可以在其运行启动前利用 --volumes-from 参数:

1
docker run [-it/-d] --volumes-from <container_a> IMAGE

Dockerfile

Dockerfile 是一个用来构建镜像的文本文件,文本内容包含了一条条构建镜像所需的指令和说明

简单来说,一个 Dockerfile 文件就是一个脚本文件(类似于 .sh 文件),通过它我们可以使用 build 命令 一键实现对镜像的构建,区别于以往不断在容器内定制内容最后反复 commit 的繁琐过程。

Dockerfile 文件的文本内容模板如下,每行开头全大写的关键词我们称之为“保留字”,是 Dockerfile 的重要组成部分,表明应该做的事情。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 符号`#`用于注释, 注释必须单独一行

# 引入已存在于本地的原镜像(指定版本号)
FROM image:tag

# (可选)Dockerfile作者和邮箱
MAINTAINER author<author@mail.com>

# 定义环境变量/全局变量 (eg. 定义工作目录)
ENV <key> <value>
ENV <key1>=<value1> <key2>=<value2>...
ENV WORK_PATH /usr/local

#设置后续指令的工作目录
WORKDIR $WORK_PATH

#执行RUN这个保留字后面跟着的shell命令, 有两种格式 (eg. 安装vim)
RUN <命令行命令>
RUN ["可执行文件", "参数1", "参数2"]
RUN apt-get install vim



CMD

  • shell 格式
  • exec 格式

注意:如果 Dockerfile 中如果存在多个 CMD 指令,仅最后一个生效。

build

Dockerfile 文件目录下,运行下列命令以构建新的镜像:

1
docker build IMAGE:TAG .

注意末尾有一个点 . 不能丢!

Docker网络

当我们在通过 sudo systemctl start docker启动Docker服务后,主机会产生一个名为 docker0虚拟网桥。(可通过 ifconfig 查看验证)

通过下列命令我们可以查看 Docker 的网络模式:

1
docker network ls

一般有三大模式:bridgehostnone

相关网络命令

通过 docker network --help 可查看所有可用的命令:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
localhost:~ # docker network --help

Usage: docker network COMMAND

Manage networks

Commands:
connect Connect a container to a network
create Create a network
disconnect Disconnect a container from a network
inspect Display detailed information on one or more networks
ls List networks
prune Remove all unused networks
rm Remove one or more networks

Run 'docker network COMMAND --help' for more information on a command.

参考

  1. Docker 教程 | 菜鸟教程
  2. 容器 VS 虚拟机 - redhat.com
  3. 尚硅谷Docker实战教程2022年版 - bilibili