同一个 Dockerfile 上的不同条件
Different conditionals on the same Dockerfile
我有一个 Dockerfile,其中包含一些我想有条件地使用的命令:
FROM + image_name
(我有一个 M1 芯片 MacOS,所以我需要添加 --platform=linux/amd64
但我想部署在不需要它的 AWS EC2 linux 实例中)
- 在生产环境中,我想 运行 我的项目使用 nginx,所以我希望 Dockerfile 以此
RUN mkdir -p tmp/sockets
结尾。但是为了测试,我不需要 nginx,所以我希望我的 Dockerfile 以此结尾
# Expose port
EXPOSE 3000
# Start rails
CMD ["rails", "server", "-b", "0.0.0.0"]
我想使用 multi stage dockerfile
来解决 FROM image
问题,但是生成的 Dockerfile 非常冗长,因为它除了 FROM image
部分外基本相同。
对于 nginx
部分,我想使用 shell 脚本,但我不确定如何编写公开端口和最终命令来启动 rails。
这些是文件:
run_dockerfile.sh
#!/bin/bash
if [ ${RUN_DOCKERFILE} = "PROD" ]; then
mkdir -p tmp/sockets
else
????
fi
我的 Dockerfile
看起来像这样:
# Start from the official ruby image
# To run Dockerfile with arm64 architecture (M1 chip MacOS for example)
FROM --platform=linux/amd64 ruby:2.6.6 AS ARM64
# Set environment
ARG BUILD_DEVELOPMENT
# if --build-arg BUILD_DEVELOPMENT=1, set RAILS_ENV to 'development' or set to null otherwise.
ENV RAILS_ENV=${BUILD_DEVELOPMENT:+development}
# if RAILS_ENV is null, set it to 'production' (or leave as is otherwise).
ENV RAILS_ENV=${RAILS_ENV:-production}
# Update and install JS & DB
RUN apt-get update -qq && apt-get install -y nodejs postgresql-client
# Create a directory for the application and use it
RUN mkdir /myapp
WORKDIR /myapp
# Gemfile and lock file need to be present, they'll be overwritten immediately
COPY Gemfile /myapp/Gemfile
COPY Gemfile.lock /myapp/Gemfile.lock
# Install gem dependencies
RUN gem install bundler:2.2.32
RUN bundle install
RUN curl https://deb.nodesource.com/setup_12.x | bash
ADD https://dl.yarnpkg.com/debian/pubkey.gpg /tmp/yarn-pubkey.gpg
RUN apt-key add /tmp/yarn-pubkey.gpg && rm /tmp/yarn-pubkey.gpg
RUN echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list
RUN apt-get update -qq && apt-get install -y yarn && apt-get install -y npm
RUN yarn add bootstrap
COPY . /myapp
# So that webpacker compiles
RUN yarn config set ignore-engines true
RUN rm -rf bin/webpack*
RUN rails webpacker:install
RUN bundle exec rails webpacker:compile
RUN bundle exec rake assets:precompile
# This script runs every time the container is created, necessary for rails
COPY entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]
# Run run_dockerfile.sh
COPY run_dockerfile.sh run_dockerfile.sh
RUN chmod u+x run_dockerfile.sh && ./run_dockerfile.sh
##################################################
# Start from the official ruby image
# To run Dockerfile without arm64 architecture
FROM ruby:2.6.6 AS AMD64
# Set environment
ARG BUILD_DEVELOPMENT
# if --build-arg BUILD_DEVELOPMENT=1, set RAILS_ENV to 'development' or set to null otherwise.
ENV RAILS_ENV=${BUILD_DEVELOPMENT:+development}
# if RAILS_ENV is null, set it to 'production' (or leave as is otherwise).
ENV RAILS_ENV=${RAILS_ENV:-production}
# Update and install JS & DB
RUN apt-get update -qq && apt-get install -y nodejs postgresql-client
# Create a directory for the application and use it
RUN mkdir /myapp
WORKDIR /myapp
# Gemfile and lock file need to be present, they'll be overwritten immediately
COPY Gemfile /myapp/Gemfile
COPY Gemfile.lock /myapp/Gemfile.lock
# Install gem dependencies
RUN gem install bundler:2.2.32
RUN bundle install
RUN curl https://deb.nodesource.com/setup_12.x | bash
ADD https://dl.yarnpkg.com/debian/pubkey.gpg /tmp/yarn-pubkey.gpg
RUN apt-key add /tmp/yarn-pubkey.gpg && rm /tmp/yarn-pubkey.gpg
RUN echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list
RUN apt-get update -qq && apt-get install -y yarn && apt-get install -y npm
RUN yarn add bootstrap
COPY . /myapp
# So that webpacker compiles
RUN yarn config set ignore-engines true
RUN rm -rf bin/webpack*
RUN rails webpacker:install
RUN bundle exec rails webpacker:compile
RUN bundle exec rake assets:precompile
# This script runs every time the container is created, necessary for rails
COPY entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]
# Run run_dockerfile.sh
COPY run_dockerfile.sh run_dockerfile.sh
RUN chmod u+x run_dockerfile.sh && ./run_dockerfile.sh
我有什么办法可以做到 .sh
或者有什么正确的建议吗?谢谢!
从你描述问题的方式来看,你根本不需要很多特殊情况。
一个重要的细节是,当您 运行 一个容器时,很容易覆盖图像的 CMD
。例如,如果您有 two Compose files,您可以只设置服务的 command:
# docker-compose.yml
version: '3.8'
services:
myapp:
image: registry.example.com/myapp:${MYAPP_TAG:-latest}
ports: ['3000:80']
# docker-compose.override.yml
# for developer use
version: '3.8'
services:
myapp:
build: .
command: rails server -b 0.0.0.0 -p 80
您列出的其他变体应该无关紧要。如果您在 x86-64 主机上构建映像 FROM --platform=linux/amd64
,并明确指定本机平台,您应该会得到一致的结果; RUN mkdir
您不会使用的目录是无害的。一个不一致的地方似乎是容器端口,但您可以明确告诉 rails server
使用哪个端口以便它匹配。我会在所有环境中使用相同的图像。
FROM --platform=linux/amd64 ruby:2.6.6 # even on an Intel/AMD host system
...
RUN mkdir tmp/sockets # even if it's unused
CMD ["nginx", "-g", "daemon off;"] # can be overridden when the container runs
我有一个 Dockerfile,其中包含一些我想有条件地使用的命令:
FROM + image_name
(我有一个 M1 芯片 MacOS,所以我需要添加--platform=linux/amd64
但我想部署在不需要它的 AWS EC2 linux 实例中)- 在生产环境中,我想 运行 我的项目使用 nginx,所以我希望 Dockerfile 以此
RUN mkdir -p tmp/sockets
结尾。但是为了测试,我不需要 nginx,所以我希望我的 Dockerfile 以此结尾
# Expose port
EXPOSE 3000
# Start rails
CMD ["rails", "server", "-b", "0.0.0.0"]
我想使用 multi stage dockerfile
来解决 FROM image
问题,但是生成的 Dockerfile 非常冗长,因为它除了 FROM image
部分外基本相同。
对于 nginx
部分,我想使用 shell 脚本,但我不确定如何编写公开端口和最终命令来启动 rails。
这些是文件:
run_dockerfile.sh
#!/bin/bash
if [ ${RUN_DOCKERFILE} = "PROD" ]; then
mkdir -p tmp/sockets
else
????
fi
我的 Dockerfile
看起来像这样:
# Start from the official ruby image
# To run Dockerfile with arm64 architecture (M1 chip MacOS for example)
FROM --platform=linux/amd64 ruby:2.6.6 AS ARM64
# Set environment
ARG BUILD_DEVELOPMENT
# if --build-arg BUILD_DEVELOPMENT=1, set RAILS_ENV to 'development' or set to null otherwise.
ENV RAILS_ENV=${BUILD_DEVELOPMENT:+development}
# if RAILS_ENV is null, set it to 'production' (or leave as is otherwise).
ENV RAILS_ENV=${RAILS_ENV:-production}
# Update and install JS & DB
RUN apt-get update -qq && apt-get install -y nodejs postgresql-client
# Create a directory for the application and use it
RUN mkdir /myapp
WORKDIR /myapp
# Gemfile and lock file need to be present, they'll be overwritten immediately
COPY Gemfile /myapp/Gemfile
COPY Gemfile.lock /myapp/Gemfile.lock
# Install gem dependencies
RUN gem install bundler:2.2.32
RUN bundle install
RUN curl https://deb.nodesource.com/setup_12.x | bash
ADD https://dl.yarnpkg.com/debian/pubkey.gpg /tmp/yarn-pubkey.gpg
RUN apt-key add /tmp/yarn-pubkey.gpg && rm /tmp/yarn-pubkey.gpg
RUN echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list
RUN apt-get update -qq && apt-get install -y yarn && apt-get install -y npm
RUN yarn add bootstrap
COPY . /myapp
# So that webpacker compiles
RUN yarn config set ignore-engines true
RUN rm -rf bin/webpack*
RUN rails webpacker:install
RUN bundle exec rails webpacker:compile
RUN bundle exec rake assets:precompile
# This script runs every time the container is created, necessary for rails
COPY entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]
# Run run_dockerfile.sh
COPY run_dockerfile.sh run_dockerfile.sh
RUN chmod u+x run_dockerfile.sh && ./run_dockerfile.sh
##################################################
# Start from the official ruby image
# To run Dockerfile without arm64 architecture
FROM ruby:2.6.6 AS AMD64
# Set environment
ARG BUILD_DEVELOPMENT
# if --build-arg BUILD_DEVELOPMENT=1, set RAILS_ENV to 'development' or set to null otherwise.
ENV RAILS_ENV=${BUILD_DEVELOPMENT:+development}
# if RAILS_ENV is null, set it to 'production' (or leave as is otherwise).
ENV RAILS_ENV=${RAILS_ENV:-production}
# Update and install JS & DB
RUN apt-get update -qq && apt-get install -y nodejs postgresql-client
# Create a directory for the application and use it
RUN mkdir /myapp
WORKDIR /myapp
# Gemfile and lock file need to be present, they'll be overwritten immediately
COPY Gemfile /myapp/Gemfile
COPY Gemfile.lock /myapp/Gemfile.lock
# Install gem dependencies
RUN gem install bundler:2.2.32
RUN bundle install
RUN curl https://deb.nodesource.com/setup_12.x | bash
ADD https://dl.yarnpkg.com/debian/pubkey.gpg /tmp/yarn-pubkey.gpg
RUN apt-key add /tmp/yarn-pubkey.gpg && rm /tmp/yarn-pubkey.gpg
RUN echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list
RUN apt-get update -qq && apt-get install -y yarn && apt-get install -y npm
RUN yarn add bootstrap
COPY . /myapp
# So that webpacker compiles
RUN yarn config set ignore-engines true
RUN rm -rf bin/webpack*
RUN rails webpacker:install
RUN bundle exec rails webpacker:compile
RUN bundle exec rake assets:precompile
# This script runs every time the container is created, necessary for rails
COPY entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]
# Run run_dockerfile.sh
COPY run_dockerfile.sh run_dockerfile.sh
RUN chmod u+x run_dockerfile.sh && ./run_dockerfile.sh
我有什么办法可以做到 .sh
或者有什么正确的建议吗?谢谢!
从你描述问题的方式来看,你根本不需要很多特殊情况。
一个重要的细节是,当您 运行 一个容器时,很容易覆盖图像的 CMD
。例如,如果您有 two Compose files,您可以只设置服务的 command:
# docker-compose.yml
version: '3.8'
services:
myapp:
image: registry.example.com/myapp:${MYAPP_TAG:-latest}
ports: ['3000:80']
# docker-compose.override.yml
# for developer use
version: '3.8'
services:
myapp:
build: .
command: rails server -b 0.0.0.0 -p 80
您列出的其他变体应该无关紧要。如果您在 x86-64 主机上构建映像 FROM --platform=linux/amd64
,并明确指定本机平台,您应该会得到一致的结果; RUN mkdir
您不会使用的目录是无害的。一个不一致的地方似乎是容器端口,但您可以明确告诉 rails server
使用哪个端口以便它匹配。我会在所有环境中使用相同的图像。
FROM --platform=linux/amd64 ruby:2.6.6 # even on an Intel/AMD host system
...
RUN mkdir tmp/sockets # even if it's unused
CMD ["nginx", "-g", "daemon off;"] # can be overridden when the container runs