> ## Content Index
> Fetch the complete content index at: https://www.richarvin.com/llms.txt
> Use this file to discover other available public pages before exploring further.

# Docker学习笔记（基础篇）一
- URL: https://www.richarvin.com/docker-xue-xi-bi-ji-ji-chu-pian-yi/
- Published: 2024-03-09T06:32:53.000Z
- Updated: 2024-05-22T01:33:32.000Z
- Author: Richarvin
- Tags: 编程技术

## 一、Docker简介

---

## Docker的出现背景

在Docker出现之前，软件的开发、测试和生产环境之间的一致性问题、应用的部署和扩展难题、以及不同环境下的配置复杂性等，一直是开发和运维团队面临的常见问题：

1. 环境不一致  
开发人员经常遇到“在我的机器上运行正常”的问题，当代码被移植到新的环境（比如测试或生产环境）时，由于操作系统、库版本和其他环境设置的差异，应用可能无法正常运行。
2. 配置管理复杂  
随着应用和服务的增长，管理不同环境（开发、测试、生产）的配置变得越来越复杂。每个环境可能需要不同的配置文件和设置，这使得维护成本显著增加。
3. 部署和扩展困难  
传统的虚拟化解决方案，如虚拟机，提供了一定程度的环境隔离和资源分配，但它们通常资源开销大，启动慢，使得快速部署和自动扩展应用变得更加困难。

## 什么是Docker?

Docker是一个开源的容器化平台，它允许开发者将应用及其依赖打包成一个轻量级、可移植的容器，然后这个容器可以在任何支持Docker的系统上运行，不论这个系统是开发者的本地机器、私有云还是公有云。容器像虚拟机一样，拥有自己独立的文件系统，但与虚拟机不同的是，容器共享宿主机的内核，而不需要模拟整个操作系统，因此它们启动更快，资源开销更小。所以说，docker的出现很好的解决了上述的那些问题：

1. 环境一致性  
Docker容器为应用提供了包括代码、运行时、系统工具、系统库等在内的完整运行环境，确保了从开发到生产的环境一致性。
2. 快速、可重复的部署  
由于Docker容器的轻量级特性，它们可以在几秒钟内启动，这使得部署过程变得迅速和可重复。开发者可以快速地在任何地方启动、停止和复制容器。
3. 开发和运维的协同  
Docker通过Dockerfile等工具，使得基础设施的定义和应用部署过程可编码、版本控制，从而促进了开发和运维团队之间的协同工作。
4. 资源高效和隔离  
与传统虚拟机相比，Docker容器共享宿主机的内核，而不是虚拟化一个完整的操作系统，因此它们占用的资源更少，启动更快。同时，Docker提供了容器间的隔离机制，保证了安全性。

## Docker的核心概念

- ### 镜像（Images）[\[1\]](#fn1)

Docker镜像是一个只读的模板，包含了运行容器所需要的文件系统和应用。镜像可以被用来创建Docker容器。Docker镜像通常通过Dockerfile来定义和构建，Dockerfile是一个包含了创建镜像所需步骤的文本文件。比方说原本一个ubuntu非桌面版服务器完整版的镜像大概是1-2GB左右，但是其docker版本的只有70MB左右，为什么这么小？因为这些镜像通常基于 Ubuntu 的最小化版本构建，仅包含了运行最基本系统所必需的文件和工具。这种镜像称为“Ubuntu Base Image”，它去除了所有不必要的文件，比如UI组件、文档、和其他默认安装的软件，从而大大减少了镜像的大小。这样做的目的是为了优化性能，确保Docker容器尽可能轻量级，启动更快，且占用较少的磁盘空间。当我们pull了一个这样的镜像运行起来后，你发现里面并没有vim和ifconfig等工具，那么这个时候A、B两个人都可以基于这个基础镜像各自在上面安装两个工具做为自己的镜像给别人使用。

- ### 容器（Containers）

Docker容器是由镜像创建的运行实例。你可以把它看作是一个简化版的Linux环境，包括应用和其所有依赖，但是共享主机的内核。容器可以被启动、停止、移动和删除。

- ### 仓库（Repositories）

Docker仓库是用于存储和分享镜像的地方。最著名的Docker镜像仓库是Docker Hub，它提供了数以万计的镜像供下载。私有和公有的仓库都可以帮助团队和组织分享和管理镜像。

---

1. 当我们使用docker pull命令拉取一个Docker镜像时，可能会看到多行输出，显示正在下载多个文件。这是因为Docker镜像的层级结构正是利用了联合文件系统（Union File System，UnionFS）的特性来实现的。联合文件系统是一种特殊的文件系统，能够将多个不同的文件系统（在Docker的上下文中指的是镜像层）叠加在一起，形成一个统一的文件系统视图。这使得每个镜像层都可以被单独修改和存储，同时又能够以一种透明的方式被叠加和访问。这种设计有几个重要的优势：1、重用和共享：不同的镜像可以共享相同的层。例如如果多个镜像都是从同一个基础操作系统镜像构建的，那么这个操作系统层只需要存储和下载一次。这不仅节省了存储空间，也加快了镜像的下载和部署速度；2、增量更新：当镜像更新时，只需要下载改变的那部分层。例如，如果你更新了一个应用的代码，但基础环境没有变，那么只有包含代码变化的那一层需要被更新和下载。这使得拉取更新变得更快，因为你不需要重新下载整个镜像；3、效率和速度：通过重用已有的层，Docker能够更快地构建和传输镜像。所以当你拉取一个Docker镜像时，实际上是在逐层下载它的所有层。如果这是你第一次拉取该镜像，或者该镜像有很多更新的层，你将看到多个层被下载。一旦某个层被下载并存储在你的系统中，当你拉取使用相同层的其他镜像时，Docker就可以重用这些层，而不是再次下载它们。这也解释了为什么有时候拉取镜像非常快——很多层已经存在于你的系统中了。 [↩︎](#fnref1)

## 二、安装和配置Docker

---

Docker支持多种平台，包括Windows、MacOS和基于Linux的操作系统。下面分别介绍在这些平台上安装Docker的步骤。

#### Linux（Ubuntu）

**1.**更新索引并设置存储库：  
打开终端并执行以下命令以更新本地软件包列表：

```bash
#更新索引库
sudo apt-get update

#允许apt通过HTTPS的的方式安装存储库
sudo apt-get install ca-certificates curl gnupg

```

2.添加密钥：

```bash
#用超级用户权限,创建一个权限为755的/etc/apt/keyrings目录
sudo install -m 0755 -d /etc/apt/keyrings

#从Docker下载它的GPG公钥,并存放到系统的密钥托管目录 /etc/apt/keyrings/ 下
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg

#使用超级用户权限,给/etc/apt/keyrings/docker.gpg这个文件添加所有用户的读权限
sudo chmod a+r /etc/apt/keyrings/docker.gpg
```

**3.**使用以下命令设置存储库：

```bash
#使用root权限,在/etc/apt/sources.list.d/docker.list文件中写入一个Docker的APT源定义。以便系统的源列表中添加了Docker的软件仓库。
echo \
  "deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
  "$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

```

4.**添加Docker的官方GPG密钥**：

```bash
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

```

5.**再次更新软件包索引**：

```bash
sudo apt-get update

```

6.**安装Docker** ：

```bash
#安装Docker Engine、containerd和Docker Compose插件的最新版本
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

#安装Docker Compose组件
sudo apt install docker-compose

#设置docker开机自启
systemctl enable docker
```

7.**验证Docker是否成功安装**：

```bash
sudo docker run hello-world

```

这条命令会下载一个名为hello-world的镜像并在容器中运行。如果安装成功，你将看到一条欢迎消息"Hello from Docker!",如下图所示：

![](https://picture.richarvin.com/202403/xnip2024-03-09_11-01-13.webp)

运行run这条命令的时候，每次它会先从本地磁盘中搜索是否有一个名为hello-world的镜像，如果本地磁盘中有，则直接运行该镜像实例，如果没有，则从上面第4步我们默认设置的docker官方仓库地址搜索下载运行，如果官方仓库中也没有该镜像，则会显示“No repositories found matching "foobar"。

#### Windows（客户端方式）

1. **下载Docker Desktop for Windows**：
<!DOCTYPE html> 

[Docker官网](https://www.docker.com/?ref=richarvin.com) 

1. **运行安装程序**：  
右键以管理员的身份运行安装下载的安装程序。系统可能会要求你启用WSL 2或Hyper-V特性。

![](https://picture.richarvin.com/202403/xnip2024-03-09_11-34-27.jpg)

1. **重启计算机**：  
安装完成后，根据提示重启计算机。

**启动Docker Desktop**：  
重启后，启动Docker Desktop。

**验证安装**：  
打开终端或命令提示符，输入以下命令：

```bash
docker run hello-world

```

#### MacOS（客户端安装）

同理windows安装类型

## 三、配置Docker环境

---

安装Docker之后，需要进行一些配置优化自己的Docker环境：

1. **用户组配置**：

默认情况下，运行`docker`命令需要`sudo`权限。可以通过将用户添加到`docker`组来避免每次都需要输入`sudo`：

```bash
sudo usermod -aG docker your-username

```

1. **配置Docker开机自启**：

```bash
sudo systemctl enable docker

```

1. **Docker镜像加速**(切换国内的云仓库)：

以阿里云镜像仓库地址为例，登录

<!DOCTYPE html> 

[阿里云企业应用中心](https://promotion.aliyun.com/ntms/act/kubernetes.html?ref=richarvin.com) 

用自己的淘宝账号或者支付宝登录，进入控制台首页，在产品容器列表中找到“容器镜像服务ACR”，根据自己的需求开通个人版或者企业版。

![](https://picture.richarvin.com/202403/xnip2024-03-09_12-25-36.webp)

开通后，在“容器镜像服务ACR”页面的左侧列表中找到“镜像工具”-“镜像加速器”：

![](https://picture.richarvin.com/202403/xnip2024-03-09_12-41-11.webp)

将自己的加速器地址复制到图中下方的粉色地方替换掉，然后整块代码（不要包括下面的中文注释）拷贝在服务器中运行即可：

```bash
# 指定路径下创建名为docker的配置目录
sudo mkdir -p /etc/docker

# 创建或修改/etc/docker/daemon.json文件，并写入配置信息
sudo tee /etc/docker/daemon.json <<-'EOF'
{
  # 指定Docker拉取镜像时使用的镜像加速地址
  "registry-mirrors": ["你自己的加速器地址"]
}
EOF

# 重新加载系统守护进程的配置，以确保Docker的配置更改被识别
sudo systemctl daemon-reload

# 重启Docker服务，应用新的配置
sudo systemctl restart docker

```

1. 设置自己的私有仓库

使用Docker自带的`registry`镜像来运行一个私有仓库。以下是创建私有Docker仓库的基本步骤：

**启动Registry容器**：

```bash
#从阿里云镜像仓库下载registry:2镜像，并创建一个自定义名为registry的容器，将容器的5000端口映射到主机的5000端口，同时主机的/registry-data目录挂载到容器的/var/lib/registry目录，最终以守护进程模式启动该容器。
docker run -d -p 5000:5000 --name registry -v /registry-data:/var/lib/registry registry:2

```

注意：在今后的生产环境中指定具体的版本号能确保环境的一致性和可重复性，避免默认的latest可能会因为时间长了，同伴拉取的版本不一样引发意外的问题。

1. 推送镜像至私有仓库

默认情况下，Docker 客户端只允许通过 HTTPS 连接到 registry。如果你的环境中使用的是 HTTP 或者自签名的证书，你需要配置 Docker 客户端以允许这种连接。docker安装后默认没有daemon.json这个配置文件，需要进行手动创建配置。

```bash
vim /etc/docker/daemon.json
```

文件中新增如下命令并保存：

```bash
{
 "registry-mirrors": ["阿里云镜像加速器地址"]，
 "insecure-registries": ["your-server-ip:5000"] 
} 
```

重启 Docker 服务以应用更改：

```bash
sudo systemctl restart docker

```

上传镜像至私有仓库：

```bash
sudo docker push your-server-ip:5000/your-image:tag
```

从私有仓库下载镜像：

```bash
sudo docker pull your-server-ip:5000/your-image:tag

```

## 四、docker镜像的构建方式

---

### 使用 `docker commit` 创建镜像

假设你正在运行一个 Ubuntu 容器，并在其中安装了 Apache 服务器。现在你想把这个容器及其更改保存为一个新的镜像。

**1.启动容器**：首先你会启动一个基于 Ubuntu 的容器：

```bash
docker run -it ubuntu /bin/bash

```

**2.安装 Apache**：在容器内部，安装 Apache 服务器：

```bash
apt-get update && apt-get install -y apache2

```

**3.退出容器**：安装完成后退出容器：

```bash
exit
```

4.使用 `docker commit` 创建一个新的镜像：

```bash
#这里的[容器ID]是你之前运行容器的ID
docker commit [容器ID] my-apache-image

```

通过 `docker commit`，你快速地将一个已经修改过的容器状态保存成了一个新的镜像： `my-apache-image`。这个方法简单粗暴，适合于快速保存或实验。

### 使用 `docker build` 创建镜像

假设你同样想创建一个包含 Apache 服务器的 Ubuntu 镜像，但这次你打算使用 `docker build` 和 Dockerfile。

**1.创建 Dockerfile**：首先，在一个空目录中创建一个名为 `Dockerfile` 的文件，内容如下：

```bash
FROM ubuntu
RUN apt-get update && apt-get install -y apache2
CMD ["apachectl", "-D", "FOREGROUND"]

```

这个 Dockerfile 做了三件事：

- 从官方的 Ubuntu 镜像开始作为基础。
- 安装 Apache 服务器。
- 设置默认命令来运行 Apache 服务器。

**2.构建镜像**：在 Dockerfile 所在的目录下运行以下命令来构建镜像：

```bash
#注意通常build命令构建结尾有个空格和.的符号。这个点代表Dockerfile所在的上下文路径，也就是 Docker构建过程中的工作目录。如果Dockerfile就在当前目录下，使用 .表示当前目录作为构建上下文发送给Docker daemon。
docker build -t my-apache-image .

```

这会根据Dockerfile中定义的步骤自动构建镜像。通过 docker build 和Dockerfile，你创建了一个具有完全相同功能的镜像 my-apache-image。这种方法的优点是构建过程完全自动化且可重复，更容易理解、维护和分享。Dockerfile文档中详细说明了你的镜像是如何被构建的。

两者区别：  
docker commit对于快速原型制作和即时更改很有用，但可能导致“黑盒”镜像，难以追踪内容和更改。  
docker build虽然设置起来需要更多的时间，但其结果是可维护的、文档化的，更适合于团队合作和长期项目。