【问题标题】:Docker-compose and dockerfile - spoil with common mistakesDocker-compose 和 dockerfile - 常犯错误
【发布时间】:2020-10-01 15:40:09
【问题描述】:

假设我有一个应用程序,我想测试某人是否知道如何处理 docker。为此,我准备了带有简单 docker-compose.yml 的工作 dockerfile,作为我使用 Rails 应用程序的示例,如下所示:

dockerfile

FROM ruby:2.7.1

RUN apt-get update -qq && apt-get install -y nodejs

RUN mkdir /app
WORKDIR /app

COPY Gemfile Gemfile.lock ./
RUN gem install bundler
RUN bundle install

# Copy the main application.
COPY . ./

# Expose the applications port to the host machine
EXPOSE 3000

# Command to run when the container is started.
CMD bundle exec rails s -p 3000 -b '0.0.0.0'

docker-compose.yml

version: '3.8'

services:
  app:
    build: .
    command: bundle exec rails s -p 3000 -b '0.0.0.0'
    volumes:
      - .:/app
    ports:
      - "3000:3000"

entrypoint.sh

#!/bin/bash
set -e

# Remove a potentially pre-existing server.pid for Rails.
rm -f /myapp/tmp/pids/server.pid

# Then exec the container's main process (what's set as CMD in the Dockerfile).
exec "$@"

所以现在我想用一些常见的错误来打破这些工作设置 - 你知道这些常见的错误吗?可能会删除端口或更改 dockerfile 中的应用程序位置,此类设置中常见的错误是什么?

【问题讨论】:

  • 在我看来,您应该始终 (1) 关注 best practices,(2) 不要忘记实际设置您所拥有的 ENTRYPOINT,(3) 始终固定无论您要安装什么(最好将版本传递为ARG 并将版本保存在容器ENV 中),(4)lint your Dockerfile 和(5)在多行上拆分apt-get updateapt-get install,在apt -get install 中设置--no-install-recommends,(6)WORKDIR 创建目录..
  • 声明一个入口点而不使用它已经很有趣了。如果你想让它变得复杂,你可以重现这个问题中的错误:stackoverflow.com/questions/64156551/…
  • 可以把它交给code review,并可以在考虑我如何故意搞砸之前向您展示我要更改的所有内容。
  • 这是我为工作创建的故意破坏项目的示例:github.com/yields-io/broken-minimal-keycloak

标签: ruby-on-rails docker docker-compose


【解决方案1】:

TL;DR;

如果您想测试他们对docker 的了解,那么您的Dockerfile 已经被常见错误宠坏了。如果它正在测试他们对从您的Dockerfile 构建的映像创建的容器内运行的任何内容的了解,那么这取决于应用程序的功能,以及如果您尝试测试它们的一般调试应用程序的能力,那么天空是您可以让它们从操作系统的错误二进制文件、错误的文件权限、编码问题、资源分配、网络...


当前的常见错误

  1. "Split long or complex RUN statements on multiple lines separated with backslashes ..."
  2. 固定您正在安装的 apt 软件包的版本(注意:这是迄今为止我看到的最常见的错误)
  3. 不要安装apt推荐的你不需要的包
  4. "When you clean up the apt cache by removing /var/lib/apt/lists it reduces the image size ..."
  5. "the instructions RUN, COPY, ADD create layers"WORKDIR 指令将在目录不存在时创建该目录 - 删除 RUN mkdir app 会从最终图像中删除一层
  6. 固定gem 包的版本
  7. RUN 指令中的链式命令可减少最终图像中的层数
  8. Dockerfile 中设置ENTRYPOINT 指令
  9. CMDENTRYPOINT 参数使用 JSON 表示法

注意:基于debain 的图像perform cleanup after every apt-get install 但如果您没有明确删除apt 文件,hadolint 会报错。您可以忽略掉毛错误或在安装后显式清理,我更喜欢后者。

hadolint'd 版本的 Dockerfile

FROM ruby:2.7.1

RUN apt-get update && \
    apt-get install -y --no-install-recommends \
        nodejs=10.21.0~dfsg-1~deb10u1 && \
    rm -rf /var/lib/apt/lists/*

WORKDIR /app

COPY Gemfile Gemfile.lock ./
RUN gem install bundler:2.1.4 && \ 
    bundle install

COPY . ./

EXPOSE 3000

ENTRYPOINT ["entrypoint.sh"]
CMD ["bundle", "exec", "rails", "s", "-p", "3000", "-b", "'0.0.0.0'"]

关于docker-compose 配置,设置command 是多余的:

version: '3.8'
services:
  app:
    build: .
    volumes:
      - .:/app
    ports:
      - "3000:3000"

...关于开放的端口,这实际上取决于您的期望。如果您希望该人建议您映射端口是 meh,并且您应该将流量代理到服务(即通过 nginx),那么是的,这应该被视为一个问题。

其他常见错误

我经常遇到的常见错误的非详尽列表:

  1. COPY'ing a tar 存档成图像,然后在 2 条指令中解压缩 tar
COPY files.tar.gz /
RUN tar czvf files.tar.gz

可以替换为ADD(从最终图像中删除一层),即:ADD files.tar.gz /

  1. 更改目录然后解压缩tar 文件
RUN cd / && tar xzvf files.tar.gz

可以在解压缩文件之前使用tar-C 选项更改目录,即tar -C / xzvf files.tar.gz

  1. curl'ing tar 文件然后在 2 个 RUN's 中解压缩它们
RUN curl -Lo files.tar.gz https://example.com/files.tar.gz
RUN tar xzvf files.tar.gz

可以在单个RUN 指令中将pipecurl 输出到tar,即:curl https://example.com/files.tar.gz | tar xzv

  1. 使用pipe 而不设置SHELL 选项^ 应该是:
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
RUN curl https://example.com/files.tar.gz | tar -C / xzv
  1. COPY'ing 来自 multi-staged build 的不应复制到最后一层的东西:
FROM debian:buster-slim as build
# build everything
FROM scratch as target
COPY --from=build /some/random/file .
  1. COPY'ing 将秘密放入构建中(使用 buildkit 和您的 ssh-agent 在构建中克隆存储库)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-05-04
    • 1970-01-01
    • 1970-01-01
    • 2021-08-21
    • 1970-01-01
    • 2021-08-19
    • 2019-11-21
    • 1970-01-01
    相关资源
    最近更新 更多