Skip to content

Commit d581766

Browse files
authored
Reduce default Docker image size in 7.x (#75079)
The `centos:8` image hasn't been updated for a while, and now the image layer for updating it via `yum` is larger than the base image. Address this by adopting the strategy for 8.0, where we build a custom base image from `centos:8` and use that instead. The implementation here differs in that `yum` is still available in the custom image, making it more like the CentOS image, and therefore less breaking than the 8.0 changes. Before: 1.04GB After: 806MB
1 parent 3a6e90c commit d581766

File tree

1 file changed

+135
-21
lines changed

1 file changed

+135
-21
lines changed

distribution/docker/src/docker/Dockerfile

Lines changed: 135 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -18,26 +18,16 @@
1818
Note that this file is also filtered to squash together newlines, so we can
1919
add as many newlines here as necessary to improve legibility.
2020
*/ %>
21+
22+
<% if (docker_base == "ubi") { %>
2123
################################################################################
2224
# Build stage 0 `builder`:
2325
# Extract Elasticsearch artifact
2426
################################################################################
25-
26-
${build_args}
27-
2827
FROM ${base_image} AS builder
2928
30-
<% if (docker_base == 'ubi') { %>
3129
# Install required packages to extract the Elasticsearch distribution
3230
RUN <%= retry.loop(package_manager, "${package_manager} install -y findutils tar gzip") %>
33-
<% } %>
34-
35-
<% if (docker_base == 'iron_bank') { %>
36-
# `tini` is a tiny but valid init for containers. This is used to cleanly
37-
# control how ES and any child processes are shut down.
38-
COPY tini /bin/tini
39-
RUN chmod 0755 /bin/tini
40-
<% } else { %>
4131
4232
# `tini` is a tiny but valid init for containers. This is used to cleanly
4333
# control how ES and any child processes are shut down.
@@ -59,6 +49,108 @@ RUN set -eux ; \\
5949
mv \${tini_bin} /bin/tini ; \\
6050
chmod +x /bin/tini
6151
52+
<% } else if (docker_base == 'iron_bank') { %>
53+
################################################################################
54+
# Build stage 0 `builder`:
55+
# Extract Elasticsearch artifact
56+
################################################################################
57+
58+
${build_args}
59+
60+
FROM ${base_image} AS builder
61+
62+
# `tini` is a tiny but valid init for containers. This is used to cleanly
63+
# control how ES and any child processes are shut down.
64+
COPY tini /bin/tini
65+
RUN chmod 0755 /bin/tini
66+
67+
<% } else { %>
68+
69+
<% /* CentOS builds are actaully a custom base image with a minimal set of dependencies */ %>
70+
71+
################################################################################
72+
# Step 1. Create a minimal root filesystem directory. This will form the basis
73+
# for our image.
74+
################################################################################
75+
FROM ${base_image} AS rootfs
76+
77+
ENV TINI_VERSION 0.19.0
78+
79+
# Start off with an up-to-date system
80+
RUN ${package_manager} update --setopt=tsflags=nodocs -y
81+
82+
# Create a directory into which we will install files
83+
RUN mkdir /rootfs
84+
85+
# Create required devices
86+
RUN mkdir -m 755 /rootfs/dev && \\
87+
mknod -m 600 /rootfs/dev/console c 5 1 && \\
88+
mknod -m 600 /rootfs/dev/initctl p && \\
89+
mknod -m 666 /rootfs/dev/full c 1 7 && \\
90+
mknod -m 666 /rootfs/dev/null c 1 3 && \\
91+
mknod -m 666 /rootfs/dev/ptmx c 5 2 && \\
92+
mknod -m 666 /rootfs/dev/random c 1 8 && \\
93+
mknod -m 666 /rootfs/dev/tty c 5 0 && \\
94+
mknod -m 666 /rootfs/dev/tty0 c 4 0 && \\
95+
mknod -m 666 /rootfs/dev/urandom c 1 9 && \\
96+
mknod -m 666 /rootfs/dev/zero c 1 5
97+
98+
# Install a minimal set of dependencies, and some for Elasticsearch
99+
RUN ${package_manager} --installroot=/rootfs --releasever=/ --setopt=tsflags=nodocs \\
100+
--setopt=group_package_types=mandatory -y \\
101+
install bash curl findutils nc procps-ng shadow-utils unzip yum zip
102+
103+
# `tini` is a tiny but valid init for containers. This is used to cleanly
104+
# control how ES and any child processes are shut down.
105+
#
106+
# The tini GitHub page gives instructions for verifying the binary using
107+
# gpg, but the keyservers are slow to return the key and this can fail the
108+
# build. Instead, we check the binary against the published checksum.
109+
RUN set -e ; \\
110+
TINI_BIN="" ; \\
111+
case "\$(arch)" in \\
112+
aarch64) \\
113+
TINI_BIN='tini-arm64' ; \\
114+
;; \\
115+
x86_64) \\
116+
TINI_BIN='tini-amd64' ; \\
117+
;; \\
118+
*) echo >&2 "Unsupported architecture \$(arch)" ; exit 1 ;; \\
119+
esac ; \\
120+
curl --retry 10 -S -L -O "https://github.com/krallin/tini/releases/download/v0.19.0/\${TINI_BIN}" ; \\
121+
curl --retry 10 -S -L -O "https://github.com/krallin/tini/releases/download/v0.19.0/\${TINI_BIN}.sha256sum" ; \\
122+
sha256sum -c "\${TINI_BIN}.sha256sum" ; \\
123+
rm "\${TINI_BIN}.sha256sum" ; \\
124+
mv "\${TINI_BIN}" /rootfs/bin/tini ; \\
125+
chmod +x /rootfs/bin/tini
126+
127+
RUN echo "NETWORKING=yes" > /rootfs/etc/sysconfig/network && \\
128+
echo "HOSTNAME=localhost.localdomain" >> /rootfs/etc/sysconfig/network
129+
130+
# Cleanup the filesystem
131+
RUN ${package_manager} --installroot=/rootfs -y clean all && \\
132+
cd /rootfs && \\
133+
rm -rf \\
134+
sbin/sln \\
135+
usr/{{lib,share}/locale,{lib,lib64}/gconv,bin/localedef,sbin/build-locale-archive} \\
136+
usr/share/{man,doc,info,gnome/help} \\
137+
usr/share/cracklib \\
138+
usr/share/i18n \\
139+
var/cache/yum && \\
140+
mkdir -p --mode=0755 var/cache/yum
141+
142+
# ldconfig
143+
RUN rm -rf /rootfs/etc/ld.so.cache /rootfs/var/cache/ldconfig && \\
144+
mkdir -p --mode=0755 /rootfs/var/cache/ldconfig
145+
146+
# Ensure that there are no files with setuid or setgid, in order to mitigate "stackclash" attacks.
147+
RUN find /rootfs -xdev -perm -4000 -exec chmod ug-s {} +
148+
149+
################################################################################
150+
# Step 2. Fetch the Elasticsearch distribution and configure it for Docker
151+
################################################################################
152+
FROM ${base_image} AS builder
153+
62154
<% } %>
63155
64156
RUN mkdir /usr/share/elasticsearch
@@ -100,6 +192,8 @@ RUN sed -i -e 's/ES_DISTRIBUTION_TYPE=tar/ES_DISTRIBUTION_TYPE=docker/' bin/elas
100192
find . -xdev -perm -4000 -exec chmod ug-s {} + && \\
101193
find . -type f -exec chmod o+r {} +
102194

195+
<% if (docker_base == "ubi" || docker_base == "iron_bank") { %>
196+
103197
################################################################################
104198
# Build stage 1 (the actual Elasticsearch image):
105199
#
@@ -109,25 +203,39 @@ RUN sed -i -e 's/ES_DISTRIBUTION_TYPE=tar/ES_DISTRIBUTION_TYPE=docker/' bin/elas
109203

110204
FROM ${base_image}
111205

112-
<% if (docker_base == "iron_bank") { %>
206+
<% if (docker_base == "ubi") { %>
207+
208+
RUN <%= retry.loop(
209+
package_manager,
210+
"${package_manager} update --setopt=tsflags=nodocs -y && \n" +
211+
" ${package_manager} install --setopt=tsflags=nodocs -y \n" +
212+
" nc shadow-utils zip unzip findutils procps-ng && \n" +
213+
" ${package_manager} clean all"
214+
) %>
215+
216+
<% } else { %>
217+
113218
<%
114219
/* Reviews of the Iron Bank Dockerfile said that they preferred simpler */
115-
/* scripting so this version doesn't have the retry loop featured below. */
220+
/* scripting so this version doesn't have the retry loop featured above. */
116221
%>
117222
RUN ${package_manager} update --setopt=tsflags=nodocs -y && \\
118223
${package_manager} install --setopt=tsflags=nodocs -y \\
119224
nc shadow-utils zip findutils unzip procps-ng && \\
120225
${package_manager} clean all
121226
227+
<% } %>
228+
122229
<% } else { %>
123230
124-
RUN <%= retry.loop(
125-
package_manager,
126-
"${package_manager} update --setopt=tsflags=nodocs -y && \n" +
127-
" ${package_manager} install --setopt=tsflags=nodocs -y \n" +
128-
" nc shadow-utils zip unzip ${docker_base == 'ubi' ? 'findutils procps-ng' : ''} && \n" +
129-
" ${package_manager} clean all"
130-
) %>
231+
################################################################################
232+
# Stage 3. Build the final image, using the rootfs above as the basis, and
233+
# copying in the Elasticsearch distribution
234+
################################################################################
235+
FROM scratch
236+
237+
# Setup the initial filesystem.
238+
COPY --from=rootfs /rootfs /
131239
132240
<% } %>
133241
@@ -140,7 +248,10 @@ ENV ELASTIC_CONTAINER true
140248
141249
WORKDIR /usr/share/elasticsearch
142250
COPY --from=builder --chown=1000:0 /usr/share/elasticsearch /usr/share/elasticsearch
251+
252+
<% if (docker_base == "ubi" || docker_base == "iron_bank") { %>
143253
COPY --from=builder --chown=0:0 /bin/tini /bin/tini
254+
<% } %>
144255
145256
ENV PATH /usr/share/elasticsearch/bin:\$PATH
146257
@@ -203,7 +314,10 @@ COPY LICENSE /licenses/LICENSE.addendum
203314
USER elasticsearch:root
204315
<% } %>
205316

317+
# Our actual entrypoint is `tini`, a minimal but functional init program. It
318+
# calls the entrypoint we provide, while correctly forwarding signals.
206319
ENTRYPOINT ["/bin/tini", "--", "/usr/local/bin/docker-entrypoint.sh"]
320+
207321
# Dummy overridable parameter parsed by entrypoint
208322
CMD ["eswrapper"]
209323

0 commit comments

Comments
 (0)