Docker 基础

‍‍

初识容器

首先在机器上安装好docker,并且通过命令行确认状态。

image

尝试从官方镜像仓库拉取镜像

Docker 会默认从 docker.io 官方镜像仓库中搜索。

:latest​指的是获取最新的版本,也可以手动指定版本号

1
$ docker pull lyzhang1999/hello-world-flask:latest

使用命令列出所有可用的镜像(images)

1
$ docker images

image

运行镜像

1
2
$ docker run -d -p 8000:5000 lyzhang1999/hello-world-flask:latest

-d 代表“在后台运行容器”,同时它会输出容器 ID,这是运行容器的唯一标识。

-p 代表“将容器内的 5000 端口暴露到宿主机(本地的 8000 端口)”,这可以方便我们在本地进行访问。

看到下面的输出说明我们成功启动了 hello-world-flask 镜像。

image

打开浏览器访问 localhost:8000,可以看到:

image

连接容器

首先查看运行中的容器列表,找到CONTAINER ID

1
2
3
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c3f7297de428 lyzhang1999/hello-world-flask:latest "python3 -m flask ru…" 2 minutes ago Up 2 minutes 0.0.0.0:8000->5000/tcp cool_mendel

执行命令进入容器内部:

1
$ docker exec -it c3f7297de428 bash

-it 的含义是“保持 STDIN 打开状态,并且分配一个虚拟的终端(Terminal)”。可以简单理解为,我们通过 SSH 登录到了容器内部,在当前终端下运行的所有命令都是基于容器内的

返回的结果如下

image

尝试编辑容器内部的文件app.py​,保存并退出

image

再次访问 http://localhost:8000 可以看到页面已经发生了变化

输入exit​退出容器

1
root@c3f7297de428:/app# exit

最后可以输入以下命令停止容器

1
$ docker stop [容器id]

例如

image

关于容器和镜像

通俗地说,镜像是一个同时包含业务应用和运行环境的“系统安装包”,它需要运行起来之后才能提供服务,运行后镜像的“实例化”称为容器(Container)。你可以对同一个镜像实例化多次,产生多个独立的容器,这些容器拥有不同的容器 ID,不同的容器之间是相互隔离的。

进一步理解,你可以把容器比喻为虚拟机,虚拟机也是,彼此之间的数据和状态都是隔离的。

构建镜像

使用 Python 编写的 Flask Web 应用作为例子

复制以下代码,并保存为app.py

1
2
3
4
5
6
7
8
9
from flask import Flask
import os
app = Flask(__name__)
app.run(debug=True)

@app.route('/')
def hello_world():
return 'Hello, my first docker images! ' + os.getenv("HOSTNAME") + ''

这段代码的含义非常简单,启动一个 Web 服务器,当接收到 HTTP 请求时,返回 “Hello, my first docker images!” 以及 HOSTNAME 环境变量。

接下来,创建 Python 的依赖文件 requirements.txt ,用它来安装依赖的 Flask 框架。你可以执行下面的命令来创建 requirements.txt 文件并将 Flask==2.2.2 内容写入该文件。

1
$ echo "Flask==2.3.3" >> requirements.txt

有了这两个文件,我们已经可以在本地启动这个 Python Web 应用了。

image

接下来,将这段最简单的 Python 业务代码制作成镜像。

我们需要一个文件来描述镜像是如何被构建的,这个文件叫做 Dockerfile​。

将以下内容保存为 Dockerfile 文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# syntax=docker/dockerfile:1

FROM python:3.8-slim-buster

RUN apt-get update && apt-get install -y procps vim apache2-utils && rm -rf /var/lib/apt/lists/*

WORKDIR /app

COPY requirements.txt requirements.txt
RUN pip3 install -r requirements.txt

COPY . .

CMD [ "python3", "-m" , "flask", "run", "--host=0.0.0.0"]

解释一下 Dockerfile 文件里的这几个命令

第一行以 syntax 开头的是解析器注释,它与 Docker 构建镜像的工具 buildkit 相关,在一般情况,建议使用 docker/dockerfile:1,它代表始终指向最新的语法版本。

FROM 命令,表示使用官方仓库的 python:3.8-slim-buster 镜像作为基础镜像。在我们熟悉的编程方法中,可以理解为从该镜像继承。这个镜像已经安装了 Python3 和 Pip3 等所有的 Python 相关的工具和包,我们可以直接使用。

RUN 的含义是在镜像内运行指定的命令,这里我们为镜像安装了一些必要的工具。 WORKDIR 的含义是镜像的工作目录,你可以理解为后续所有的命令都将以此为基准路径。这样,我们就可以在后续的命令中使用相对路径而不是完整路径了。

COPY 的含义是将本地的文件或目录复制到镜像内指定的位置。第一个参数代表本地文件或目录,第二个参数代表要复制到镜像内的位置。例如,第七行 COPY 表示,将本地当前目录下的 requirements.txt 文件复制到镜像工作目录 /app 中,文件命名同样为 requirements.txt。 第十行 RUN 的含义是在镜像里运行 pip3 安装 Python 依赖。请注意,这些依赖将会被安装在镜像里而不是本地。 接下来,第十行又出现了一个 COPY 命令,它的含义是将当前目录所有的源代码复制到镜像的工作目录 /app 下,复制目录的语法和我们之前提到的复制文件是类似的。 最后一行 CMD 的含义是镜像的启动命令。在一个 Dockerfile 中,只能有一个 CMD 命令,如果有多个,那么只有最后一个 CMD 命令会起作用。例如,我们希望在镜像被运行时启动 Python Flask Web 服务器,并监听在特定主机上。CMD 的第一个参数 python3 是我们希望运行的可执行命令,后面的参数表示运行 python3 命令所需要的参数。

准备构建第一个镜像

确保当前目录下有所需的文件

image

在当前目录下执行命令

1
2
$ docker build -t hello-docker-flask .

-t 代表的是镜像名。这里隐含了镜像版本,Docker 会默认用 latest 作为版本号,也就是说,hello-docker-flask 与 hello-docker-flask:latest 的写法是等价的。

此外,还需要注意最后面有一个 “.” ,这代表了构建镜像的上下文。

执行这条命令时,Docker 会帮我们从官方镜像仓库拉取 python:3.8-slim-buster 镜像,并启动该镜像。接下来,该容器会依次执行我们在 Dockerfile 中书写的命令,例如 WORKDIR、COPY、RUN 等等。

如果遇到fail to authorize​的异常,需要指定用户和密码,并重启docker

image

查看本地镜像,并运行

1
2
$ docker images
$ docker run -d -p 8000:5000 hello-docker-flask:latest

使用命令查看容器启动情况

1
docker logs [容器ID]

可以看到容器启动正常

image

打开浏览器访问 localhost:8000,可以看到正常输出

共享镜像

为了能够在团队中共享镜像,需要先注册一个 Docker HUB 的账号,并且使用 docker login 登录,这和我们使用的 Git 工具类似。

接下来,使用 docke tag 重命名我们之前在本地构建的镜像。

1
2
$ docker tag hello-world-flask my_dockerhub_name/hello-world-flask

这里需要把 my_dockerhub_name​ 替换为你实际的 Docker Hub 账户名,也称为镜像仓库的名字

然后,我们就可以使用 docker push 把本地的镜像上传到 Docker Hub 了。

1
$ docker push my_dockerhub_name/hello-world-flask

成功上传后,其他人可以通过 docker pull 命令来拉取我们上传的镜像。

例如

image

image

0%