cmd向对方发送键盘指令_Docker-第3部分:十二个Dockerfile指令

b93c598b767893f05d60bb6b8329b28b.png
原文作者:Jeff Hale
原文地址: https:// towardsdatascience.com/ learn-enough-docker-to-be-useful-b0b44222eef5
翻译:付新圆

本篇文章是关于Dockerfiles的,这是Docker系列文章的第三部分。如果您还没有读过第1部分,请先阅读它,您可以从全新的角度了解Docker容器概念。第2部分是Docker生态系统的简要介绍。在以后的文章中,我将研究精简Docker映像、Docker CLI命令以及使用Docker的数据。 现在,让我们跳进这十几个Dockerfile说明中去吧!

e4a286173ab9f043a56c2e5bb7277c9d.png
图:跳进来

Docker映像

Docker容器是栩栩如生的Docker映像,它是一个独立的、最小的操作系统,带有应用程序代码。

Docker映像在构建时创建的,而Docker容器是在运行时创建。

Dockerfile是Docker的核心,Dockerfile告诉Docker如何构建用于制作容器的映像。

每个Docker映像都包含一个名为Dockerfile的文件,没有扩展名。调用Dockerfile docker build创建映像时,假定该Dockerfile位于当前工作目录中,可以使用文件标志(-f)指定其他位置。

容器是由一系列层构建而成的,除位于最后一层之上的最终容器层外,每一层都是只读的。Dockerfile告诉Docker添加哪些层以及添加顺序。

每一层实际上只是一个文件,其中包含自上一层以来的更改。在Unix中,几乎所有内容都是文件。

基础图像提供了初始层,基本图像也称为父图像。

当图像从远程存储库拉到本地计算机时,只下载本地计算机上尚未存在的层。Docker就是通过重用现有层来节省空间和时间。

07ec560dc72492859de121984f9bacff.png
图:基本(跳跃)图像

Dockerfile指令是一行开头的大写单词,后跟其参数。Dockerfile中的每一行都可以包含一条指令。构建图像时,说明从上到下进行处理。说明如下:

FROM ubuntu:18.04
COPY . /app

只有指令FROM,RUN,COPY和ADD才能在最终图像中创建图层,其他的指令可配置事物,添加元数据或告诉Docker在运行时执行某些操作,例如公开端口或运行命令。

在本文中,我假设您正在使用基于Unix的Docker映像。您也可以使用基于Windows的映像,但这是一个较慢,较不愉快,较不常见的过程。因此,如果可以,请使用Unix。

让我们快速浏览一下我们将探索的十二个Dockerfile指令吧。

Dockerfile指令

FROM—指定基本(父)图像。

LABEL—提供元数据,包括维护者信息。

ENV—设置持久性环境变量。

RUN—运行命令并创建图像层,用于将软件包安装到容器中。

COPY-将文件和目录复制到容器。

ADD-将文件和目录复制到容器,可以支持本地.tar文件。

CMD—为执行中的容器提供命令和参数,可以覆盖参数,只能有一个CMD。

WORKDIR—为以下说明设置工作目录。

ARG—定义在构建时传递给Docker的变量。

ENTRYPOINT—为执行中的容器提供命令和参数。争论依然存在。

EXPOSE—暴露端口。

VOLUME —创建目录安装点以访问和存储持久数据。

让我们开始吧!

说明和示例

Dockerfile可以像下面这样简单:

FROM ubuntu:18.04

FROM

Dockerfile必须以FROM指令或ARG指令开头,后跟FROM指令。

FROM 关键字告诉Docker使用与提供的存储库和标签匹配的基础映像,基本图像也称为父图像。

在此示例中,ubuntu是映像存储库。Ubuntu是官方Docker存储库的名称,该存储库提供了流行的Linux操作系统的Ubuntu版本的基本版本。

f65d82abdab9d1b218661cfa5f82d4b9.png
图:Linux吉祥物Tux

请注意,此Dockerfile包含基础映像的标记:18.04,这个标签告诉Docker在ubuntu仓库中镜像的哪个版本。如果不包含标签,则默认情况下,Docker将采用最新标签。为了使您的意图清晰明了,最好指定一个基本图像标签。

当上述Dockerfile首次用于在本地构建映像时,Docker下载ubuntu映像中指定的层。可以将这些层视为彼此堆叠。每一层都是一个文件,具有与前一层不同的一组文件。

创建容器时,可以在只读层的顶部添加可写层。

6e5c5738b8a7f1d29371728afd380ef6.png
图:从Docker文档

为了提高效率,Docker使用了一种写时拷贝策略。如果一个层存在于图像的前一层,而另一层需要对其进行读访问,Docker将使用现有文件。不需要下载任何内容。

当一个图像正在运行时,如果一个层需要被容器修改,那么该文件将被复制到顶部的可写层中。

更具实质性的Dockerfile

虽然我们的单线图很简洁,但它也很慢,提供的信息很少,并且在容器运行时什么也不做。让我们看一个较长的Dockerfile,它构建一个小得多的图像,并在容器运行时执行脚本。

FROM python:3.7.2-alpine3.8
LABEL maintainer="jeffmshale@gmail.com"
ENV ADMIN="jeff"
RUN apk update && apk upgrade && apk add bash
COPY . ./app
ADD https://raw.githubusercontent.com/discdiver/pachy-vid/master/sample_vids/vid1.mp4 
/my_app_directory
RUN ["mkdir", "/a_directory"]
CMD ["python", "./my_script.py"]

这是怎么回事能?让我们逐步了解并揭开神秘面纱。

基本映像是带有标签3.7.2-alpine3.8的正式Python映像。从源代码中可以看到,该映像包含Linux、Python和其他一些内容。高山图像之所以受欢迎,是因为它们体积小,速度快且安全。但是,Alpine映像并没有很多操作系统优点。如果需要,您必须自己安装这样的软件包。

LABEL

下一条指令是LABEL。LABEL将元数据添加到图像中。在本例中,它提供图像维护者的联系信息。 Labels不会减慢构建速度或占用空间,它们提供了有关Docker映像的有用信息,因此一定要使用它们。有关LABEL元数据的更多信息,请参见此处。

53f2471c91256e3953f9e5c7da8c2321.png

ENV

ENV设置在容器运行时可用的持久环境变量。在上面的例子中,您可以在创建Docker容器时使用ADMIN变量。

ENV非常适合设置常量,如果您在Dockerfile中的多个位置使用常量,并且想在以后更改其值,则可以在一个位置进行更改。

526a61f4e750eeabe7034bcb512d7d97.png
图:环境

对于Dockerfiles,通常可以通过多种方式完成同一件事。针对您的案例,最好的方法是平衡Docker约定、透明性和速度。例如,RUN、CMD和ENTRYPOINT具有不同的用途,并且均可用于执行命令。

RUN

RUN在构建时创建一个层。每次运行后,Docker都会提交映像的状态。

RUN通常用于将软件包安装到映像中在上面的示例中,RUN apk update && apk upgrade告诉Docker从基础映像更新软件包&& apk add bash告诉Docker将bash安装到映像中。

apk代表Alpine Linux软件包管理器。如果您使用的是Alpine以外的其他版本的Linux基础映像,则应使用RUN apt-get而不是apk安装软件包。apt代表高级包工具。在后面的示例中,我将讨论安装包的其他方法。

42a9fff229e634d650ca38dca1c91b6f.png
图:跑

RUN及其同级命令CMD和ENTRYPOINT可以在exec表单或shell表单中使用。Exec form使用的JSON数组语法如下:

例如:RUN ["my_executable", "my_first_param1", "my_second_param2"]

在上面的示例中,我们使用格式为的shell形式RUN apk update && apk upgrade && apk add bash

稍后在Dockerfile中,我们使用首选的exec形式RUN ["mkdir", "/a_directory"]创建目录。别忘了对exec form使用JSON语法的字符串使用双引号!

COPY

COPY . ./app 指令告诉Docker在本地构建上下文中获取文件和文件夹,并将它们添加到Docker映像的当前工作目录中。如果不存在,复制将创建目标目录。

55b18f1e600947be64eebc7e52d765e2.png
图:复制

ADD

ADD与COPY执行相同的操作,但有两个以上的用例。ADD可用于将文件从远程URL移动到容器,ADD可以提取本地TAR文件。

我在上面的示例中使用ADD将文件从远程URL复制到容器的my_app_directory中。Docker文档不建议以这种方式使用远程URL,因为您无法删除这些文件。额外的文件会增加最终图像的大小。

Docker文档还建议尽可能使用COPY而不是ADD来提高清晰度。Docker没有将ADD和COPY合并到一个命令中,以减少Dockerfile指令的数量来保持直线,这太糟糕了。

注意,ADD指令包含换行符,使用它可以通过将一条长指令拆分成几行来提高可读性。

CMD

CMD向Docker提供了一个在容器启动时运行的命令。它不会在构建时将命令的结果提交给映像。在上面的示例中,CMD将使Docker容器在运行时运行my_ script.py文件。

95f29e17681006788ed04eda20d6f3a0.png
图:那是CMD!

有关CMD的其他几件事:

  • 每个Dockerfile仅一个CMD指令。否则,除最后一个以外的所有内容都将被忽略。
  • CMD可以包含一个可执行文件。如果存在没有可执行文件的CMD,则必须存在ENTRYPOINT指令。在这种情况下,CMD和ENTRYPOINT指令都应为JSON格式。
  • 命令行参数将docker run覆盖Dockerfile中提供给CMD的参数。

准备好了吗?

让我们在另一个Dockerfile示例中介绍更多说明。

FROM python:3.7.2-alpine3.8
LABEL maintainer="jeffmshale@gmail.com"
# Install dependencies
RUN apk add --update git
# Set current working directory
WORKDIR /usr/src/my_app_directory
# Copy code from your local context to the image working directory
COPY . .
# Set default value for a variable
ARG my_var=my_default_value
# Set code to run at container run time
ENTRYPOINT ["python", "./app/my_script.py", "my_var"]
# Expose our port to the world
EXPOSE 8000
# Create a volume for data storage
VOLUME /my_volume

请注意,您可以在Dockerfiles中使用注释。注释以#开头。

软件包安装是Dockerfiles的主要工作。如前所述,有几种方法可以使用RUN安装软件包。

您可以使用apk在Alpine Docker映像中安装软件包,apk就像常规Linux构建中的apt-get。例如,带有基本Ubuntu映像的Dockerfile中的软件包可以像这样更新和安装:RUN apt-get update && apt-get install my_package

除了apk和apt-get之外,还可以通过pip,wheel和conda安装Python软件包。其他语言可以使用各种安装程序。

基础层需要向安装层提供相关的软件包管理器。如果您在安装软件包时遇到问题,请在安装软件包管理器之前尝试使用它们。

您可以将RUN与pip一起使用,并在Dockerfile中直接列出要安装的软件包。如果这样做,则将您的软件包安装到一条指令中,并用换行符()将其分开。与多个RUN指令相比,此方法提供了清晰度和更少的层数。

或者,您可以在文件中列出软件包要求,然后在该文件上运行软件包管理器。人们通常将文件命名为requirements.txt。我将在下一篇文章中分享一个推荐的模式,以利用http://build.ca缓存与requirements.txt一起使用。

WORKDIR

WORKDIR会更改容器中的工作目录,以供后面的COPY、ADD、RUN、CMD和ENTRYPOINT指令使用。几点注意事项:

  • 最好使用WORKDIR设置绝对路径,而不是使用Dockerfile中的cd命令在文件系统中导航。
  • 如果该目录不存在,则WORKDIR会自动创建该目录。
  • 您可以使用多个WORKDIR指令。如果提供了相对路径,则每个WORKDIR指令都会更改当前工作目录。

acab4d4fd6ba8c7ccb5181f1b29bb6a0.png
图:某种工作目录

ARG

ARG定义了一个在构建时从命令行传递到映像的变量。可以在Dockerfile中为ARG提供默认值,如示例所示:ARG my_var=my_default_value

与ENV变量不同,ARG变量不适用于运行中的容器。但是,在生成映像时,可以使用ARG值在命令行中为ENV变量设置默认值。然后,ENV变量在容器运行期间一直存在。

ENTRYPOINT

ENTRYPOINT指令还允许您在容器启动时提供默认命令和参数。它看起来与CMD相似,但是如果使用命令行参数运行容器,则ENTRYPOINT参数不会被覆盖。

而是将传递给的命令行参数docker run my_image_name附加到ENTRYPOINT指令的参数中。例如,docker run my_image bash将参数bash添加到ENTRYPOINT指令的现有参数的末尾。

3fe8d022aaf3095d0106d1168249bc4c.png
图:进入某处

Dockerfile应该至少具有一个CMD或ENTRYPOINT指令。

Docker文档中有一些关于在CMD和ENTRYPOINT之间选择初始容器命令的建议:

  • 当您需要每次运行相同的命令时,请选择ENTRYPOINT。
  • 当容器将用作可执行程序时,首选入口点。
  • 当您需要提供额外的默认参数,可以从命令行重写时,使用CMD。

在上面的示例中,ENTRYPOINT ["python", "my_script.py", "my_var"]让容器在容器开始运行时运行带有参数my_var的python脚本my_script.py 。然后,my_script可以通过argparse使用my_var。请注意,my_var具有ARG先前在Dockerfile中提供的默认值。因此,如果未从命令行传递参数,则将使用默认参数。

Docker建议您通常使用ENTRYPOINT:的exec形式ENTRYPOINT ["executable", "param1", "param2"]。这种形式是使用JSON数组语法的形式。

EXPOSE

EXPOSE指令显示要发布哪个端口以提供对正在运行的容器的访问。EXPOSE实际上不会发布端口。相反,它充当构建映像的人员与运行容器的人员之间的文档。

e314077c83ba411d3f509e8dbc535875.png
图:暴露

docker run-p标志一起使用,以在运行时发布和映射一个或多个端口。大写-P标志将发布所有公开的端口。

VOLUME

VOLUME指定您的容器将在哪里存储和/或访问持久数据。

e520cd73008597ffdb3b0121e21aed70.png
图:卷

总结

Dockerfile也许是Docker掌握的关键组件。我希望本文能帮助到你们。

我想将frontend 也是用volumes,将其映射到/app/frontend目录,在/app/frontend下install以及build,如何实现 docker-compose.yml文件: version: '3' services: frontend: build: context: ./frontend dockerfile: Dockerfile ports: - 8010:80 restart: always backend: build: context: ./backend dockerfile: Dockerfile volumes: - /app/backend:/app environment: - CELERY_BROKER_URL=redis://redis:6379/0 command: python manage.py runserver 0.0.0.0:8000 ports: - 8011:8000 restart: always celery-worker: build: context: ./backend dockerfile: Dockerfile volumes: - /app/backend:/app environment: - CELERY_BROKER_URL=redis://redis:6379/0 command: celery -A server worker -l info --pool=solo --concurrency=1 depends_on: - redis - backend restart: always celery-beat: build: context: ./backend dockerfile: Dockerfile volumes: - /app/backend:/app environment: - CELERY_BROKER_URL=redis://redis:6379/0 command: celery -A server beat -l info --scheduler django_celery_beat.schedulers:DatabaseScheduler depends_on: - redis - backend restart: always redis: image: redis:latest ports: - 6379:6379 restart: always mysql: image: mysql:latest environment: - MYSQL_ROOT_PASSWORD=sacfxSql258147@ ports: - 8016:3306 volumes: - ./mysql:/var/lib/mysql restart: always frontend:dockerfile文件 FROM node:16.18.1 WORKDIR /app/frontend COPY package*.json ./ RUN npm install COPY . . RUN npm run build:prod FROM nginx:latest COPY --from=0 /app/frontend/dist/ /usr/share/nginx/html EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]
最新发布
07-14
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值