本文我们将了解 Docker 中 Dockerfile、构建镜像、运行容器以及如何将镜像推送到存储库。
Docker 镜像的最基本构件是 Dockerfile。
Dockerfile 是一个包含指令和参数的简单文本文件。Docker 可以通过读取 Dockerfile 中给出的指令自动构建镜像。
在 Dokcerfile 中,左侧的所有内容都是指令,右侧的内容是这些指令的参数。需要注意的是,创建 Dockerfile,文件名就是Dockerfile
,不需要任何的扩展名。
下表总结了 Dockerfile 中重要的指令及其解释:
Dockerfile 指令 | 解释 |
---|---|
FROM | 指定可从容器注册中心(Docker hub、GCR、Quay、ECR 等)拉取的基础映像。 |
RUN | 在镜像构建过程中执行命令。 |
ENV | 设置镜像内的环境变量。它将在构建期间以及正在运行的容器中可用。如果只想购置构建过程中的变量,可以是用 ARG 指令。 |
COPY | 将本地的文件和目录复制到镜像中。 |
EXPOSE | 指定要为 Docker 容器公开暴露的端口。 |
ADD | 它是 COPY 指令的一个功能更丰富的版本。它还允许从作为源文件的 URL 复制,并将 tar 文件自动拉去到镜像中。不过,建议使用 COPY 命令而不是 ADD。如果向下载远程文件,请使用 curl 或使用 RUN 指令。 |
WORKDIR | 设置当前工作目录。我们可以在 Dockerfile 中重复使用这条指令来设置不同的工作目录。如果设置了 WORKDIR,RUN,CMD,ADD,COPY或ENTRYPOINT等指令就会在该目录下执行。 |
VOLUME | 它用于创建卷或将卷挂载到 Docker 容器。 |
USER | 设置运行容器时的用户名和 UID。我们可以使用此指令设置容器的非 root 用户。 |
LABEL | 用于指定 Dokcer 镜像的元数据信息。 |
ARG | 它用于设置带有键和值的构建时变量。当容器运行时,ARG 变量将不可用。如果我们想在正在运行的容器上保留变量,请使用 ENV 指令。 |
CMD | 它用于在正在运行的容器中执行命令。只能由一个 CMD,如果由多个 CMD,则仅适用于最后一个。它可以通过 Docker CLI 进行重写。 |
ENTRTPOINT | 指定 Docker 容器启动时将执行的命令。如果不指定任何 ENTRYPOINT,则默认为 /bin/sh -c。我们还可以适用 CLI 适用 --entrypoint标志覆盖 ENTRYPOINT。 |
下面我们来了解以下 Dockerfile 的基本组件:
基础镜像是 Docker 镜像的起点。它为我们的应用程序提供底层操作系统和环境。我们可以从 Docker Hub 上提供的各种预构建基础镜像中进行选择,例如 AIpine Linux,Centos 或 Nodejs 或 Golang 等特定语言运行时。
FROM node:14
上面的实例中,我们适用版本为 14 的 Nodejs 基础镜像。该镜像包含了 Nodejs 及其运行环境,适合运行 Nodejs 应用程序。
工作目录是容器内将复制应用程序代码的位置。将工作目录设置为特定路径是一个很好的方法。
WORKDIR /app
例子中,我们将工作目录设置为 /app
。
接下来,我们需要将应用程序代码和任何必要的文件复制到容器中的工作目录。这可确保容器具有运行应用程序所需的所有文件。
COPY package*.json ./
上面的行会将package.json
和package-lock.json
文件从主句目录复制到容器中的当前工作目录。
复制必要的文件后,我们适用 npm
,pip
或go mod
等包管理器安装应用程序的依赖项。
RUN npm install
此命令将根据package.json
文件来安装 Nodejs 的依赖项。
安装依赖项后,我们可以将应用程序的其余部分复制到容器的工作目录。
COPY . .
将行将所有文件和文件夹从主机目录复制到容器中的当前工作目录。
如果我们的应用程序需要监听特定的端口,则需要在 Dockerfile 中公开暴露该端口。
EXPOSE 3000
例子中,我们公开端口 3000,这是 Nodejs Web 应用程序的默认端口。
最后,我们需要定义容器启动时将要执行的命令。
CMD ["node", "app.js"]
此命令指定容器执行node
命令,并且app.js
文件应作为应用程序的入口点。
通过以上的指令组合到 Dockerfile 文件中,我们可以构建一个封装应用程序及其依赖项的镜像。该镜像可以作为容器在任何安装了 Docker 的系统上运行,为我 i 们的应用程序提供一致且隔离的环境。
# 拉取官方镜像
FROM node:14
# 设置工作目录
WORKDIR /app
# 从主机复制文件到工作目录
COPY package*.json ./
# npm 安装依赖
RUN npm install
# 复制程序代码到主机目录
COPY . .
# 暴露端口
EXPOSE 3000
# 运行命令行启动程序
CMD ["node", "app.js"]
上面的例子中,我们首先拉取了 Nodejs 为 14 的基础镜像。然后,将工作目录设置为/app
并复制package.json
和package-lock.json
文件到工作目录。 接着,我们适用npm install
安装 Nodejs 依赖项。接下来,我们将应用程序代码的其余部分复制到工作目录。然后公开端口 3000 以允许外部访问容器内运行的应用程序。最后,我们定义启动应用程序的命令,并将node app.js
指定为入口点。
上面的示例涵盖 Dockerfile 的基本元素,包括基本镜像选择、工作目录设置、复制文件、安装依赖项、公开端口和定义命令。我们可以根据自己的特定应用要求修改此示例,例如适用不同的基础镜像、公开不同的端口或更改入口点命令。
如下是一个 Python 示例程序,app.py
:
# app.py
# 导入 flash 模块
from flask import Flask
# 创建 Flask 应用实例
app = Flask(__name__)
# 定义跟路由 /
@app.rpute('/')
def hello():
return "Hello, world!"
# 检查脚本是否被直接执行(而不是作为模块导入)
if __name__ == '__main__':
# 运行 Flask 应用
# 在指定端口 3000 启动服务器
app.run(host='0.0.0.0', port=3000)
Dockerfile 文件:
# 拉去 Python3 基础镜像
FROM python:3
# 设置工作目录
WORKDIR /app
# 适用 pip 安装 Flask 库
RUN pip install flask
# 复制应用程序 app.py 到容器中
COPY app.py /app/
# 暴露3000端口
EXPOSE 3000
# 启动一个程序
CMD ["python", "./app.py"]
上面例子演示了如何容器化一个简单的 Flask Web 应用程序。Dockerfile 设置环境并公开端口 3000。Python 代码创建一个 Flask 应用程序,该应用程序/
路由响应:Hello,world!。
通过构建并运行 Docker 镜像,我们就可以通过端口 3000 访问 Flask 应用程序。以下终端显示如何构建镜像:
root@huang-ubuntu:~/Codes/flask_case# docker build -t flask-web-app .
[+] Building 16.0s (9/9) FINISHED docker:default
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 205B 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [internal] load metadata for docker.io/library/python:3 4.7s
=> [1/4] FROM docker.io/library/python:3@sha256:1987c4ae3b5afaa3a7c5e247e9eaab734808 0.0s
=> [internal] load build context 0.0s
=> => transferring context: 215B 0.0s
=> CACHED [2/4] WORKDIR /app 0.0s
=> [3/4] RUN pip install flask -i https://pypi.tuna.tsinghua.edu.cn/simple 10.3s
=> [4/4] COPY app.py /app/ 0.3s
=> exporting to image 0.5s
=> => exporting layers 0.4s
=> => writing image sha256:945fe2bf0a46e45118a43edc203ef5d378420e0e47578c9af7da873df 0.0s
=> => naming to docker.io/library/flask-web-app 0.0s
root@huang-ubuntu:~/Codes/flask_case# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
flask-web-app latest 945fe2bf0a46 28 seconds ago 1.03GB
首先,我们从 Dockerfile 构建 Docker 镜像:
docker build -t flask-web-app .
然后,我们使用创建的镜像运行容器:
docker run -d -p 3000:3000 flask-web-app
我们可以通过运行 docker ps
来检查 docker 容器是是否正在运行:
root@huang-ubuntu:~/Codes/flask_case# docker run -d -p 3000:3000 flask-web-app
17eca2eb0aa66f3e6d382da935ee59f099d5f7debeb7488d6e08bdc989eb8cba
root@huang-ubuntu:~/Codes/flask_case# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
17eca2eb0aa6 flask-web-app "python ./app.py" 28 seconds ago Up 26 seconds 0.0.0.0:3000->3000/tcp, :::3000->3000/tcp eager_ptolemy
可以通过在浏览器打开 http://127.0.0.1:3000/ 来验证应用程序是否正常运行:
使用 docker login
命令登录 Docker Hub:
docker login
在 Docker Hub 创建你自己的存储仓库,我的为huanggz/flask-web-app
,然后为本地镜像打上tag
标签,如下:
docker tag flask-web-app huanggz/flask-web-app
将镜像推送到 Docker Hub:
docker push huanggz/flask-web-app
root@huang-ubuntu:~/Codes/flask_case# docker tag flask-web-app huanggz/flask-web-app
root@huang-ubuntu:~/Codes/flask_case# docker push huanggz/flask-web-app
Using default tag: latest
The push refers to repository [docker.io/huanggz/flask-web-app]
2009a282a576: Pushed
d087f60c824d: Pushed
10e320de2e18: Pushed
0470b4fe10a4: Pushed
a33e56a39409: Pushed
e10f6c2422e4: Pushed
a04a14a911a5: Pushed
80bd043d4663: Pushed
30f5cd833236: Pushed
7c32e0608151: Pushed
7cea17427f83: Pushed
latest: digest: sha256:d29c9f4dafcad9e9a5d394c1dc1fa2c93b21a542f303d00f738c466d4278c7c8 size: 2631
成功推送到 Docker Hub 上: