swing构建和容器_优化容器构建的提示和技巧

swing构建和容器

获得正确的容器配置需要进行几次迭代? 每次迭代需要多长时间? 好吧,如果您回答“太多次且时间太长”,那么我的经历与您相似。 从表面上看,创建配置文件似乎是一个简单的练习:在配置文件中实现与手动安装系统时要执行的步骤相同的步骤。 不幸的是,我发现这种方法通常无法完全正常工作,并且一些“技巧”对于此类DevOps练习非常有用。

在本文中,我将分享一些发现的技术,这些技术可帮助最大程度地减少迭代次数和长度。 另外,我将概述一些超越标准的良好实践。

在上一篇有关容器化构建系统的文章的教程资料库中 ,我添加了一个名为/ tutorial2_docker_tricks的文件夹,并提供了一个示例,该示例介绍了本文中将介绍的一些技巧。 如果您想继续学习并安装了Git,可以使用以下方法在本地将其拉出:

 $  git clone https: // github.com / ravi-chandran / dockerize-tutorial 

该教程已经过Docker Desktop Edition的测试,尽管它可以与任何兼容的Linux容器系统(例如Podman )一起使用。

节省时间在容器映像构建迭代上

如果Dockerfile涉及下载并安装5GB的文件,则即使具有良好的网络速度,每次Docker 镜像构建迭代都可能会花费大量时间。 忘记包含要安装的项目可能意味着在此之后重建所有层。

解决这一难题的一种方法是使用本地HTTP服务器,以避免在Docker映像构建迭代期间多次从互联网下载大文件。 为了举例说明,假设您需要在Ubuntu 18.04下使用Anaconda 3创建一个容器映像。 Anaconda 3安装程序的文件大小约为0.5GB,因此在此示例中为“大”文件。

请注意,您不想使用COPY指令,因为它会创建一个新层。 使用大型安装程序后,还应删除它,以最大程度地减少容器映像的大小。 您可以使用多阶段构建 ,但是我发现以下方法足够有效。

其基本思想是使用基于Python的HTTP服务器在本地,以服务大文件(S),并有Dockerfile从此本地服务器wget的大文件(S)。 让我们探索如何有效设置它的细节。 提醒一下,您可以访问完整的示例

在此示例存储库中,文件夹tutorial2_docker_tricks /的必要内容是:


   
   
tutorial2_docker_tricks /
├── build_docker_image.sh                   # builds the docker image
├── run_container.sh                         # instantiates a container from the image
├── install_anaconda.dockerfile             # Dockerfile for creating our target docker image
├── .dockerignore                           # used to ignore contents of the installer/ folder from the docker context
├── installer                               # folder with all our large files required for creating the docker image
│   └── Anaconda3- 2019.10 -Linux-x86_64.sh   # from https://repo.anaconda.com/archive/Anaconda3-2019.10-Linux-x86_64.sh
└── workdir                                 # example folder used as a volume in the running container

该方法的关键步骤是:

  • 将大文件放在安装程序/文件夹中。 在此示例中,我具有大型Anaconda安装程序文件Anaconda3-2019.10-Linux-x86_64.sh 。 如果克隆我的Git存储库,则找不到该文件,因为只有您(作为容器映像创建者)需要此源文件。 图像的最终用户没有。 下载安装程序以跟随示例。
  • 创建.dockerignore文件,并使其忽略installer /文件夹,以避免Docker将所有大文件复制到构建上下文中。
  • 在终端中, cd进入tutorial2_docker_tricks /文件夹,并以./build_docker_image.sh执行构建脚本。
  • build_docker_image.sh中 ,启动Python HTTP服务器以提供来自installer /文件夹的任何文件:
    
         
         
    cd installer
    python3 -m http. server --bind 10.0.2.15 8888 &
    cd ..
  • 如果您想知道奇怪的Internet协议(IP)地址,我正在使用VirtualBox Linux VM,当我运行ifconfig时, 10.0.2.15显示为以太网适配器的地址。 该IP似乎是VirtualBox使用的约定。 如果设置不同,则需要更新此IP地址以匹配您的环境,然后更新build_docker_image.shinstall_anaconda.dockerfile 。 在此示例中,服务器的端口号设置为8888 。 请注意,IP和端口号可以作为构建参数传递,但是为了简洁起见,我对其进行了硬编码。
  • 由于HTTP服务器设置为在后台运行,请使用我发现的简洁方法使用kill -9命令在脚本末尾附近停止服务器:
     kill -9 ` ps -ef | grep http.server | grep 8888 | awk '{print $2}' 
    
  • 请注意,在脚本的前面(启动HTTP服务器之前)也使用了相同的kill -9 。 通常,当我迭代可能故意中断的任何构建脚本时,这可以确保每次HTTP服务器都干净启动。
  • Dockerfile中 ,有一条RUN wget指令,该指令从本地HTTP服务器下载Anaconda安装程序。 它还会删除安装程序文件并在安装后进行清理。 最重要的是,所有这些操作都在同一层中执行,以将图像大小保持为最小:
    
         
         
    # install Anaconda by downloading the installer via the local http server
    ARG ANACONDA
    RUN wget --no-proxy http://10.0.2.15:8888/$ { ANACONDA } -O ~/anaconda.sh \
        && /bin/bash ~/anaconda.sh -b -p /opt/conda \
        && rm ~/anaconda.sh \
        && rm -fr /var/lib/apt/lists/ { apt,dpkg,cache,log } /tmp/* /var/tmp/*
  • 此文件运行包装程序脚本anaconda.sh ,并通过使用rm删除大型文件来清理它们。
  • 构建完成后,您应该看到图像anaconda_ubuntu1804:v1 。 (您可以使用docker image ls列出图像 。)
  • 您可以使用终端中的./run_container.sh从该映像实例化容器,而该文件夹位于tutorial2_docker_tricks /文件夹中。 您可以验证Anaconda已安装:
    
         
         
    $ . / run_container.sh
    $ python --version
    Python 3.7.5
    $ conda --version
    conda 4.8.0
    $ anaconda --version
    anaconda Command line client ( version 1.7.2 )
  • 您会注意到, run_container.sh设置了一个卷workdir 。 在此示例存储库中,文件夹workdir /为空。 这是我用来设置卷的约定,可以在其中使我的Python和其他脚本独立于容器映像。

最小化容器图像大小

RUN命令等效于执行一个新的Shell,并且每个RUN命令都会创建一个图层。 用单独的RUN命令模仿安装指令的幼稚方法最终可能会在一个或多个相互依赖的步骤中中断。 如果碰巧可以正常工作,通常会产生较大的图像。 在一个RUN命令中链接多个安装步骤,并包括autoremoveautocleanrm命令(如下例所示),对于最小化每一层的大小很有用。 根据要安装的内容,可能不需要其中一些步骤。 但是,由于这些步骤花费的时间很少,因此我总是在调用apt-getRUN命令结束时将它们妥善投入:

   
   
RUN apt-get update \
    && DEBIAN_FRONTEND=noninteractive \
       apt-get -y --quiet --no-install-recommends install \
        # list of packages being installed go here \
    && apt-get -y autoremove \
    && apt-get clean autoclean \
    && rm -fr /var/lib/apt/lists/ { apt,dpkg,cache,log } /tmp/* /var/tmp/*

另外,请确保已放置.dockerignore文件,以忽略不需要发送到Docker构建上下文的项目(例如,前面示例中的Anaconda安装程序文件)。

组织构建工具I / O

对于软件构建系统,构建输入和输出(配置和调用工具的所有脚本)应在映像和最终运行的容器之外。 容器本身应保持无状态,以便不同的用户可以得到相同的结果。 我在上一篇文章中对此进行了广泛的介绍,但由于我的工作很有用,因此想强调一下。 最好通过设置容器体积来访问这些输入和输出。

我不得不使用一个容器映像,该映像以源代码和大型预构建二进制文件的形式提供数据。 作为软件开发人员,我希望在容器中编辑代码。 这是有问题的,因为默认情况下容器是无状态的:因为容器被设计为可抛弃的,所以它们不会在容器内保存数据。 但是我一直在努力,在每天结束时,我停止了容器,并且必须小心不要将其卸下,因为必须保持状态,以便我第二天才能继续工作。 这种方法的缺点是,如果有不止一个人在项目上工作,那么开发状态就会不同。 这种方法在开发人员中拥有相同的构建系统的价值在某种程度上已经丧失了。

以非root用户身份生成输出

I / O的重要方面涉及在容器中运行工具时生成的输出文件的所有权。 默认情况下,由于Docker以root身份运行,因此输出文件将归root拥有,这是不愉快的。 您通常希望以非root用户身份工作。 生成构建输出后更改所有权可以使用脚本来完成,但这是一个额外且不必要的步骤。 最好尽早在Dockerfile中设置USER参数:


   
   
ARG USERNAME
# other commands...
USER $ { USERNAME }

执行docker image build时,可以将USERNAME作为构建参数( --build-arg )传入。 您可以在示例Dockerfile和相应的构建脚本中看到一个示例。

工具的某些部分可能还需要以非root用户身份安装。 因此,如果您要直接在Linux下手动安装,则Dockerfile中的安装顺序可能需要与安装顺序不同。

非交互式安装

交互性与容器自动化相反。 我发现了

 DEBIAN_FRONTEND =noninteractive apt-get -y --quiet --no-install-recommends 

防止安装程序打开对话框所必需的apt-get install说明的选项(如上例所示)。 注意,这些选项应作为RUN指令的一部分使用。 正如FAQ所解释的那样,不应在Dockerfile中将DEBIAN_FRONTEND = noninteractive设置为环境变量( ENV ),因为它将由容器继承。

记录您的构建并运行输出

调试构建失败的原因是一项常见的任务,而日志则是完成此任务的好方法。 使用Bash脚本中的tee实用工具保存在容器映像构建或容器运行会话期间发生的所有事情的TypeScript。 换句话说,将|&tee $ BASH_SOURCE.log添加到Docker 映像构建的末尾,并在脚本中添加docker 映像运行命令。 请参阅映像构建容器运行脚本中的示例。

这种发球技术的作用是生成一个与Bash脚本同名的文件,但附加一个.log扩展名,以便您知道该文件源自哪个脚本。 运行脚本时,您在终端上看到的所有内容都将以类似的名称记录到该文件中。

这对于您的容器映像用户在无法解决问题时向您报告问题特别有价值。 您可以要求他们向您发送日志文件以帮助诊断问题。 许多工具生成的输出太多,以至于很容易使终端缓冲区的默认大小不堪重负。 仅依靠终端机的缓冲区容量来复制粘贴错误消息可能不足以诊断问题,因为以前的错误可能已经丢失。

我发现即使在容器映像构建脚本中,这也很有用,尤其是在使用上面讨论的基于Python的HTTP服务器时。 服务器在下载过程中生成了很多行,以至于通常会使终端的缓冲区不堪重负。

优雅地处理代理

在我的工作环境中,需要代理访问Internet才能下载RUN apt-getRUN wget命令中的资源。 通常从环境变量http_proxyhttps_proxy推断代理。 尽管可以使用ENV命令在Dockerfile中对此类代理设置进行硬编码,但是直接将ENV用于代理存在多个问题。

如果您是唯一可以构建容器的人,那么也许可以使用。 但是,其他位置不同的代理设置的其他人无法使用Dockerfile。 另一个问题是IT部门可能会在某个时候更改代理,从而导致Dockerfile不再起作用。 此外,Dockerfile是一个精确的文档,指定了配置受控制的系统,每项更改都将通过质量保证进行审查。

一种避免对代理进行硬编码的简单方法是,将本地代理设置作为docker image build命令中的build参数传递:


   
   
docker image build \
    --build-arg MY_PROXY =http: // my_local_proxy.proxy.com:xx

然后,在Dockerfile中,根据build参数设置环境变量。 在此处显示的示例中,您仍然可以设置默认的代理值,该值可以被上面的build参数覆盖:


   
   
# set a default proxy
ARG MY_PROXY=MY_PROXY=http://my_default_proxy.proxy.com:nn/
ENV http_proxy=$MY_PROXY
ENV https_proxy=$MY_PROXY

摘要

这些技术帮助我大大减少了创建容器映像并在出现错误时对其进行调试所需的时间。 我会继续寻找其他最佳做法,以将其添加到我的列表中。 希望以上技巧对您有所帮助。

翻译自: https://opensource.com/article/20/5/optimize-container-builds

swing构建和容器

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值