-
Notifications
You must be signed in to change notification settings - Fork 25
/
Dockerfile
254 lines (203 loc) · 8.66 KB
/
Dockerfile
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
# Stage 1: Runtime =============================================================
# The minimal package dependencies required to run the app in the release image:
# Use the official Ruby 3.0 Slim Bullseye image as base:
FROM ruby:3.0.7-slim-bullseye AS runtime
# We'll set MALLOC_ARENA_MAX for optimization purposes & prevent memory bloat
# https://www.speedshop.co/2017/12/04/malloc-doubles-ruby-memory.html
ENV MALLOC_ARENA_MAX="2"
# We'll install curl for later dependency package installation steps
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
ca-certificates \
curl \
libsqlite3-0 \
openssl \
# Required by mimemagic gem:
shared-mime-info \
tzdata \
&& rm -rf /var/lib/apt/lists/*
# Stage 2: development-base ====================================================
# This stage will contain the minimal dependencies for the rest of the images
# used to build the project:
# Use the "runtime" stage as base:
FROM runtime AS development-base
# Install the app build system dependency packages - we won't remove the apt
# lists from this point onward:
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
build-essential \
git \
libsqlite3-dev
# Receive the developer user's UID and USER:
ARG DEVELOPER_UID=1000
ARG DEVELOPER_USERNAME=you
# Replicate the developer user in the development image:
RUN addgroup --gid ${DEVELOPER_UID} ${DEVELOPER_USERNAME} \
; useradd -r -m -u ${DEVELOPER_UID} --gid ${DEVELOPER_UID} \
--shell /bin/bash -c "Developer User,,," ${DEVELOPER_USERNAME}
# Ensure the developer user's home directory and app path are owned by him/her:
# (A workaround to a side effect of setting WORKDIR before creating the user)
RUN userhome=$(eval echo ~${DEVELOPER_USERNAME}) \
&& chown -R ${DEVELOPER_USERNAME}:${DEVELOPER_USERNAME} $userhome \
&& mkdir -p /workspaces/sepomex \
&& chown -R ${DEVELOPER_USERNAME}:${DEVELOPER_USERNAME} /workspaces/sepomex
# Add the app's "bin/" directory to PATH:
ENV PATH=/workspaces/sepomex/bin:$PATH
# Set the app path as the working directory:
WORKDIR /workspaces/sepomex
# Change to the developer user:
USER ${DEVELOPER_USERNAME}
# Configure bundler to retry downloads 3 times:
RUN bundle config set --local retry 3
# Configure bundler to use 4 threads to download, build and install:
RUN bundle config set --local jobs 4
# Stage 3: Testing =============================================================
# In this stage we'll complete an image with the minimal dependencies required
# to run the tests in a continuous integration environment.
FROM development-base AS testing
# Copy the project's Gemfile and Gemfile.lock files:
COPY --chown=${DEVELOPER_USERNAME} Gemfile* /workspaces/sepomex/
# Configure bundler to exclude the gems from the "development" group when
# installing, so we get the leanest Docker image possible to run tests:
RUN bundle config set --local without development
# Install the project gems, excluding the "development" group:
RUN bundle install
# Stage 4: Development =========================================================
# In this stage we'll add the packages, libraries and tools required in our
# day-to-day development process.
# Use the "development-base" stage as base:
FROM development-base AS development
# Change to root user to install the development packages:
USER root
# Install sudo, along with any other tool required at development phase:
RUN apt-get install -y --no-install-recommends \
# Adding bash autocompletion as git without autocomplete is a pain...
bash-completion \
# gpg & gpgconf is used to get Git Commit GPG Signatures working inside the
# VSCode devcontainer:
gpg \
openssh-client \
# Para esperar a que el servicio de minio (u otros) esté disponible:
netcat \
# /proc file system utilities: (watch, ps):
procps \
# Vim will be used to edit files when inside the container (git, etc):
vim \
# Sudo will be used to install/configure system stuff if needed during dev:
sudo
# Receive the developer username argument again, as ARGS won't persist between
# stages on non-buildkit builds:
ARG DEVELOPER_USERNAME=you
# Add the developer user to the sudoers list:
RUN echo "${DEVELOPER_USERNAME} ALL=(ALL) NOPASSWD:ALL" | tee "/etc/sudoers.d/${DEVELOPER_USERNAME}"
# Persist the bash history between runs
# - See https://code.visualstudio.com/docs/remote/containers-advanced#_persist-bash-history-between-runs
RUN SNIPPET="export PROMPT_COMMAND='history -a' && export HISTFILE=/command-history/.bash_history" \
&& mkdir /command-history \
&& touch /command-history/.bash_history \
&& chown -R ${DEVELOPER_USERNAME} /command-history \
&& echo $SNIPPET >> "/home/${DEVELOPER_USERNAME}/.bashrc"
# Create the extensions directories:
RUN mkdir -p \
/home/${DEVELOPER_USERNAME}/.vscode-server/extensions \
/home/${DEVELOPER_USERNAME}/.vscode-server-insiders/extensions \
&& chown -R ${DEVELOPER_USERNAME} \
/home/${DEVELOPER_USERNAME}/.vscode-server \
/home/${DEVELOPER_USERNAME}/.vscode-server-insiders
# Change back to the developer user:
USER ${DEVELOPER_USERNAME}
# Copy the gems installed in the "testing" stage:
COPY --from=testing /usr/local/bundle /usr/local/bundle
COPY --from=testing /workspaces/sepomex/ /workspaces/sepomex/
# Configure bundler to not exclude any gem group, so we now get all the gems
# specified in the Gemfile:
RUN bundle config unset --local without
# Install the full gem list:
RUN bundle install
# Stage 5: Builder =============================================================
# In this stage we'll add the rest of the code, compile assets, and perform a
# cleanup for the releasable image.
FROM testing AS builder
# Receive the developer username argument again, as ARGS won't persist between
# stages on non-buildkit builds:
ARG DEVELOPER_USERNAME=you
# Receive the developer username argument again, as ARGS won't persist between
# stages on non-buildkit builds:
ARG DEVELOPER_USERNAME=you
# Copy the full contents of the project:
COPY --chown=${DEVELOPER_USERNAME} . /workspaces/sepomex/
# Configure bundler to exclude the gems from the "development" and "test" groups
# from the installed gemset, which should set them out to remove on cleanup:
RUN bundle config set --local without development test
# Cleanup the gems excluded from the current configuration. We'll copy the
# remaining gemset into the deployable image on the next stage:
RUN bundle clean --force
# Change to root, before performing the final cleanup:
USER root
# Remove unneeded gem cache files (cached *.gem, *.o, *.c):
RUN rm -rf /usr/local/bundle/cache/*.gem \
&& find /usr/local/bundle/gems/ -name "*.c" -delete \
&& find /usr/local/bundle/gems/ -name "*.o" -delete
# Remove project files not used on release image - be aware that files on git
# might still be copied to the image, regardless of rules in the .dockerignore
# file, whenever the image is being built on a Git context.
# - See https://docs.docker.com/engine/reference/commandline/build/#git-repositories
RUN rm -rf \
.codeclimate.yml \
.devcontainer \
.dockerignore \
.gitattributes \
.github \
.gitignore \
.reek.yml \
.rspec \
.rubocop.yml \
.simplecov \
.vscode \
Guardfile \
bin/rspec \
bin/checkdb \
bin/dumpdb \
bin/restoredb \
bin/setup \
bin/dev-entrypoint \
db/dumps \
db/seeds/development.rb \
doc \
docker-compose.yml \
Dockerfile \
log/production.log \
spec
# Stage 6: Release =============================================================
# In this stage, we build the final, releasable, deployable Docker image, which
# should be smaller than the images generated on previous stages:
# Use the "runtime" stage as base:
FROM runtime AS release
ARG DEPLOY_NAME=development
# Copy the remaining installed gems from the "builder" stage:
COPY --from=builder /usr/local/bundle /usr/local/bundle
# Copy the app code and compiled assets from the "builder" stage to the
# final destination at /workspaces/sepomex:
COPY --from=builder --chown=nobody:nogroup /workspaces/sepomex /workspaces/sepomex
# Set the container user to 'nobody':
USER nobody
# Set the RAILS and PORT default values:
ENV HOME=/workspaces/sepomex \
RAILS_ENV=production \
DEPLOY_NAME=${DEPLOY_NAME} \
RAILS_FORCE_SSL=yes \
RAILS_LOG_TO_STDOUT=yes \
RAILS_SERVE_STATIC_FILES=yes \
PORT=80
# Test if the rails app loads:
RUN SECRET_KEY_BASE=10167c7f7654ed02b3557b05b88ece rails secret > /dev/null
# Set the installed app directory as the working directory:
WORKDIR /workspaces/sepomex
# Generate the sqlite production database:
RUN rails db:create \
&& rails db:migrate \
&& rake data:load
# Set the entrypoint script:
ENTRYPOINT [ "/workspaces/sepomex/bin/entrypoint" ]
# Set the default command:
CMD [ "puma" ]