# macOS中使用Docker发布一个python项目的小纸条

最近写了一个Telegram Bot，它可以使用语音和文字与GPT进行交互，成为了我日常重度使用的工具。从练习英语的听说读，到日常的搜索使用上都让我有了不少收获。终于，日常跑在我笔记本上的日子就要过去了，我需要它能日常跑在我的服务器上，所以准备使用Docker整个image，使得我日常的更新和服务器的迁移更为简单些。所以写下这个小纸条，方便以后自己回来查看。

# 安装Docker

使用Homebrew安装简单方便：

```bash
brew install --cask docker
```

Homebrew会视你的机器安装Intel或Arm版本的Docker。然后让我们启动Docker

```bash
open /Applications/Docker.app
```

一路Next之类，这就安装好了。记得在你的配置中配置好Docker的虚拟机所使用的资源：

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1678378785168/9180879e-d157-4cba-b76c-17d57c1318b0.png align="center")

最后，点右上角的Sign in登录到你的dockerhub上。

# 本地编译image

准备好你的Dockerfile，以下是我常使用的一个为Python项目准备的Dockerfile

```bash
FROM python:latest

RUN apt-get update && apt upgrade -y
RUN cd /
COPY . /bot/
RUN cd bot
WORKDIR /bot
RUN pip install -r requirements.txt
CMD [ "python", "bot.py" ,"-c","/conf"]
```

在Dockerfile所在的文件夹中，打开终端，并构建Docker镜像。在终端中执行以下命令：

```bash
docker build -t edgebot .
```

这将使用名为“bot”的标记构建一个Docker镜像。注意，“.”代表当前目录，因此Docker将在当前目录中查找Dockerfile文件并使用它来构建镜像。此过程可能需要几分钟，具体取决于您的计算机性能和您的网络速度。

当编译好之后，你就可以在本机的镜像列表中看到edgebot了

```bash
docker image ls
```

# 运行你的image

## 从image运行

一但在docker镜像列表中看到你编译好的image，你就可以运行它了，接下来让我们尝试运行。你可以发现在Dockerfile中我们运行这个程序时有一个参数`-c`，它指定了一个配置文件的目录，我们希望运行镜像时的配置文件都从这个目录中来取得。在容器里，它的路径是`/conf`，在你的Host里，我希望它被mount指向当前目录下的`conf`目录。

```bash
docker run -v "$(pwd)/conf:/conf" edgebot
```

其中，`-v` 参数用于挂载卷。`$(pwd)` 返回当前目录的完整路径，因此 `$(pwd)/conf` 将是当前目录下的 conf 目录的完整路径。`edgebot` 是要运行的 Docker 镜像的名称。

使用这个命令，Docker 将运行指定的镜像，并将容器内的 `/conf` 目录映射到当前目录下的 `conf` 目录。这意味着您可以在当前目录下编辑配置文件，并且它们将在容器内部可见。

有时我们会遇到程序运行时出现问题，我们希望进入容器查看环境，这样就需要运行容器并起动容器内的shell了。

```bash
docker run -it -v "$(pwd)/conf:/conf" edgebot /bin/bash
```

其中，`-it` 参数用于分配一个伪终端并启用交互模式，`edgebot` 是要运行的 Docker 镜像的名称，`/bin/bash` 是要运行的 shell。

使用这个命令，Docker 将启动指定的镜像并进入容器的 shell。您现在可以在 shell 中执行命令并与容器交互。要退出 shell 并停止容器，请使用 `exit` 命令。

## 查看容器列表

一但你运行一个镜像后，Docker就会在本机自动创建一个容器。如果我们运行了上面两个命令，哪么我们可以使用以下命令查看

```bash
docker ps -a
CONTAINER ID   IMAGE     COMMAND                  CREATED         STATUS                     PORTS     NAMES
7521819b97ba   edgebot   "python edge.py -c /…"   6 minutes ago   Exited (0) 5 minutes ago             vigorous_chaplygin
fe3e828f24bd   edgebot   "python edge.py -c /…"   6 minutes ago   Exited (0) 6 minutes ago             focused_driscoll
```

`docker ps`将显示所有容器的列表，包括正在运行的容器和已经停止的容器，同样包括容器的 ID、镜像名称、状态、端口映射、创建时间等信息。如果没有`-a`参数，将只会显示正在运行的容器。

## 运行容器

要运行指定的容器，可以使用以下命令：

```bash
docker start <container_id_or_name>
```

其中，&lt;container\_id\_or\_name&gt; 是要启动的容器的 ID 或名称。

使用这个命令，Docker 将启动指定的容器并使其处于运行状态。注意，如果容器已经在运行中，则此命令不会产生任何效果。

如果要同时进入已经在运行的容器的 shell，可以使用以下命令：

```bash
docker exec -it <container_id_or_name> /bin/bash
```

其中，-it 参数用于分配一个伪终端并启用交互模式，&lt;container\_id\_or\_name&gt; 是要进入的容器的 ID 或名称，/bin/bash 是要运行的 shell。

使用这个命令，Docker 将进入指定的容器并进入容器的 shell。您现在可以在 shell 中执行命令并与容器交互。要退出 shell，请使用 `exit` 命令。

## 容器管理

## 容器名称管理

要修改容器的名称，可以使用以下命令：

```bash
docker rename <old_name> <new_name>
```

其中，&lt;old\_name&gt; 是原始的容器名称，&lt;new\_name&gt; 是要修改的新容器名称。

使用这个命令，Docker 将重命名指定的容器。请注意，容器名称必须是唯一的。

如果要查看已命名的容器的列表，可以运行以下命令：

```bash
docker ps --format "table {{.ID}}\t{{.Names}}"
```

这将显示当前计算机上所有容器的 ID 和名称列表。您可以在该列表中查找容器的名称并使用上述 `docker rename` 命令将其重命名。同样也可以加入`-a`参数也列出没有在运行的容器。

## 首次运行镜像时指定容器名称

如果要在运行镜像时指定容器的名称，可以使用以下命令：

```bash
docker run --name <container_name> <image_name>
```

其中，--name 参数用于指定容器的名称，&lt;container\_name&gt; 是您要为容器指定的名称，&lt;image\_name&gt; 是要运行的 Docker 镜像的名称。

使用这个命令，Docker 将启动指定的镜像，并使用指定的容器名称创建一个新容器。如果未指定容器名称，则 Docker 将自动生成一个随机的容器名称。

注意，容器名称必须是唯一的。如果您尝试为已经存在的容器分配一个重复的名称，则会收到一个错误消息。为了避免这种情况，请在创建容器时始终指定唯一的名称。

# 发布镜像

一般我们会要构建并将一个 Docker 镜像推送到 Docker Hub 上，可以按照以下步骤进行操作：

1. 在本地计算机上构建 Docker 镜像：
    
    ```bash
    docker build -t <username>/<image_name>:<tag> .
    ```
    
    其中，&lt;username&gt; 是您的 Docker Hub 用户名，&lt;image\_name&gt; 是您要构建的镜像名称，&lt;tag&gt; 是您要为镜像指定的标签（例如版本号）。`.` 表示使用当前目录中的 Dockerfile 构建镜像。
    
2. 运行以下命令以验证构建的镜像已经创建：
    
    ```bash
    docker images
    ```
    
    这将显示本地计算机上的所有 Docker 镜像列表，包括刚刚构建的镜像。
    
3. 使用以下命令将镜像推送到 Docker Hub：
    
    ```bash
    docker push <username>/<image_name>:<tag>
    ```
    
    其中，&lt;username&gt; 是您的 Docker Hub 用户名，&lt;image\_name&gt; 是您要推送的镜像名称，&lt;tag&gt; 是您要推送的标签。
    
    注意，您需要先登录到 Docker Hub 才能将镜像推送到您的账户。您也可以使用以下命令登录：
    
    ```bash
    docker login
    ```
    
    运行这个命令后，您需要输入您的 Docker Hub 用户名和密码。
    
4. 使用以下命令检查您刚刚推送的镜像是否已经上传到 Docker Hub：
    
    ```bash
    docker search <image_name>
    ```
    
    这将显示 Docker Hub 上所有具有指定名称的镜像列表。如果您可以看到您刚刚推送的镜像，则表示您已成功将镜像推送到 Docker Hub。
    

# 清除容器和镜像

要清除不使用的 Docker 镜像和容器，可以使用以下命令：

1. 清除所有停止的容器：
    
    ```bash
    docker container prune
    ```
    
    这将删除所有已停止的容器，这些容器不会影响任何运行中的应用程序。
    
2. 清除所有未使用的镜像和悬空的构建缓存：
    
    ```bash
    docker image prune -a
    ```
    
    这将删除所有未被任何容器使用的镜像以及悬空的构建缓存。
    
3. 清除所有未使用的卷：
    
    ```bash
    docker volume prune
    ```
    
    这将删除所有未被任何容器使用的卷。
    

注意：在执行这些命令之前，请确保您已经备份了需要保留的数据。这些命令将清除您计算机上所有未使用的容器、镜像和卷。如果您不小心清除了某些内容，可能会导致数据丢失或不可恢复。

如果您想要清除指定的 Docker 容器和镜像，可以使用以下命令：

1. 清除指定的容器：
    
    ```bash
    docker rm <container_id>
    ```
    
    其中，&lt;container\_id&gt; 是您要删除的容器的 ID。您可以使用 `docker ps -a` 命令查看所有容器的 ID。
    
    如果要删除多个容器，请使用以下命令：
    
    ```bash
    docker rm <container_id_1> <container_id_2> ...
    ```
    
2. 清除指定的镜像：
    
    ```bash
    docker rmi <image_id>
    ```
    
    其中，&lt;image\_id&gt; 是您要删除的镜像的 ID。您可以使用 `docker images` 命令查看所有镜像的 ID。
    
    如果要删除多个镜像，请使用以下命令：
    
    ```bash
    docker rmi <image_id_1> <image_id_2> ...
    ```
    

# 支持不同平台

如果要同时支持ARM64和x64架构的Docker镜像，需要在构建Dockerfile时使用多架构支持(Multi-Architecture Support)功能。

1. 在Dockerfile中包含适用于两个架构的指令和指令参数。
    

例如，下面是一个使用Alpine作为基础映像的Dockerfile示例，其中包括适用于ARM64和x64架构的指令：

```bash
# syntax = docker/dockerfile:1.2
FROM --platform=linux/amd64,linux/arm64/python:latest
WORKDIR /app
COPY . .
RUN apk add --no-cache gcc musl-dev
CMD ["./myapp"]
```

这个Dockerfile中的 `--platform=linux/amd64,linux/arm64` 参数指示Docker同时支持x64和ARM64架构。

1. 构建Docker镜像
    

使用以下命令构建Docker镜像：

```bash
docker buildx build --platform linux/amd64,linux/arm64 -t myimage:latest .
```

这个命令中的 `--platform=linux/amd64,linux/arm64` 参数告诉Docker同时构建x64和ARM64架构的镜像。

1. 验证Docker镜像
    

可以使用以下命令验证Docker镜像是否同时支持ARM64和x64架构：

```bash
docker run --rm --platform=linux/amd64,linux/arm64 myimage:latest uname -m
```

这个命令将会在容器内运行 `uname -m` 命令并输出容器的架构，如果输出中同时包含 `x86_64` 和 `aarch64`，则表示Docker镜像同时支持ARM64和x64架构。

通过使用多架构支持功能，可以轻松地在Docker容器中同时支持多种架构，并在需要时运行合适的容器。

运行`docker buildx`时有可能你会看到如下的错误信息

```bash
ERROR: multiple platforms feature is currently not supported for docker driver. Please switch to a different driver (eg. "docker buildx create --use")
```

这个错误信息是因为Docker目前的默认构建驱动程序(docker driver)不支持多架构构建。

多架构构建(Multi-Architecture Support)是Docker的一个新功能，允许构建同时支持不同架构的Docker镜像，例如x86\_64、ARM64等。

要使用多架构构建功能，需要使用Buildx驱动程序，而不是默认的Docker驱动程序。Buildx是一个构建工具，它可以在Docker中同时构建多个架构的镜像，并且可以在不同的构建平台上运行。

要解决这个错误，需要使用Buildx驱动程序。可以按照以下步骤来使用Buildx：

1. 安装Buildx插件
    

```bash
docker buildx install
```

1. 创建一个Buildx构建器
    

```bash
docker buildx create --name mybuilder
```

1. 切换到Buildx构建器
    

```bash
docker buildx use mybuilder
```

1. 构建Docker镜像
    

```bash
docker buildx build --platform linux/amd64,linux/arm64 -t myimage:latest .
```

这些命令中的 `--platform=linux/amd64,linux/arm64` 参数告诉Buildx同时构建x64和ARM64架构的镜像。

通过使用Buildx构建器，可以轻松地构建同时支持多种架构的Docker镜像，并在需要时运行合适的容器。
