Skip to content

Commit e07adb7

Browse files
authored
Support building Iron Bank Docker context (#64336)
This PR adds support for building a Docker context for Iron Bank. It doesn't actually build the image - we could add that at a later stage, but this is an attempt to automate at least some of the process. Iron Bank is a lot like our UBI build, except it uses a hardened version of the full UBI image, not the minimal UBI image. They have particular requirements around how the Docker context should be arranged. The Docker build cannot fetch its own artefacts, but instead the context provides a descriptor that locates what is needed for the build. I also added a filter so that after performing expansions on the `Dockerfile`, we squash long runs on newlines together. This makes the output cleaner, while allowing us to break up the unprocessed `Dockerfile` for clarity.
1 parent 988583e commit e07adb7

File tree

9 files changed

+192
-27
lines changed

9 files changed

+192
-27
lines changed

buildSrc/src/main/java/org/elasticsearch/gradle/DockerBase.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@
2525
public enum DockerBase {
2626
CENTOS("centos:8"),
2727
// "latest" here is intentional, since the image name specifies "8"
28-
UBI("docker.elastic.co/ubi8/ubi-minimal:latest");
28+
UBI("docker.elastic.co/ubi8/ubi-minimal:latest"),
29+
// The Iron Bank base image is UBI (albeit hardened), but we are required to parameterize the Docker build
30+
IRON_BANK("${BASE_REGISTRY}/${BASE_IMAGE}:${BASE_TAG}");
2931

3032
private final String image;
3133

distribution/docker/build.gradle

Lines changed: 61 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ import org.elasticsearch.gradle.VersionProperties
66
import org.elasticsearch.gradle.docker.DockerBuildTask
77
import org.elasticsearch.gradle.info.BuildParams
88
import org.elasticsearch.gradle.testfixtures.TestFixturesPlugin
9+
10+
import java.nio.file.Path
11+
912
apply plugin: 'elasticsearch.standalone-rest-test'
1013
apply plugin: 'elasticsearch.test.fixtures'
1114
apply plugin: 'elasticsearch.internal-distribution-download'
@@ -46,6 +49,15 @@ ext.expansions = { Architecture architecture, boolean oss, DockerBase base, bool
4649

4750
final String elasticsearch = "elasticsearch-${oss ? 'oss-' : ''}${VersionProperties.elasticsearch}-${classifier}.tar.gz"
4851

52+
String buildArgs = '#'
53+
if (base == DockerBase.IRON_BANK) {
54+
buildArgs = """
55+
ARG BASE_REGISTRY=nexus-docker-secure.levelup-nexus.svc.cluster.local:18082
56+
ARG BASE_IMAGE=redhat/ubi/ubi8
57+
ARG BASE_TAG=8.2
58+
"""
59+
}
60+
4961
/* Both the following Dockerfile commands put the resulting artifact at
5062
* the same location, regardless of classifier, so that the commands that
5163
* follow in the Dockerfile don't have to know about the runtime
@@ -61,58 +73,87 @@ RUN curl --retry 8 -S -L \\
6173
""".trim()
6274
}
6375

76+
def (major,minor) = VersionProperties.elasticsearch.split("\\.")
77+
6478
return [
6579
'base_image' : base.getImage(),
80+
'bin_dir' : base == DockerBase.IRON_BANK ? 'scripts' : 'bin',
81+
'build_args' : buildArgs,
6682
'build_date' : BuildParams.buildDate,
83+
'config_dir' : base == DockerBase.IRON_BANK ? 'scripts' : 'config',
6784
'git_revision' : BuildParams.gitRevision,
6885
'license' : oss ? 'Apache-2.0' : 'Elastic-License',
6986
'package_manager' : base == DockerBase.UBI ? 'microdnf' : 'yum',
7087
'source_elasticsearch': sourceElasticsearch,
7188
'docker_base' : base.name().toLowerCase(),
72-
'version' : VersionProperties.elasticsearch
89+
'version' : VersionProperties.elasticsearch,
90+
'major_minor_version' : "${major}.${minor}"
7391
]
7492
}
7593

94+
/**
95+
* This filter squashes long runs of newlines so that the output
96+
* is a little more aesthetically pleasing.
97+
*/
98+
class SquashNewlinesFilter extends FilterReader {
99+
SquashNewlinesFilter(Reader input) {
100+
super(new StringReader(input.text.replaceAll("\n{2,}", "\n\n")))
101+
}
102+
}
103+
76104
private static String buildPath(Architecture architecture, boolean oss, DockerBase base) {
77105
return 'build/' +
78106
(architecture == Architecture.AARCH64 ? 'aarch64-' : '') +
79107
(oss ? 'oss-' : '') +
80108
(base == DockerBase.UBI ? 'ubi-' : '') +
109+
(base == DockerBase.UBI ? 'ubi-' : (base == DockerBase.IRON_BANK ? 'ironbank-' : '')) +
81110
'docker'
82111
}
83112

84113
private static String taskName(String prefix, Architecture architecture, boolean oss, DockerBase base, String suffix) {
85114
return prefix +
86115
(architecture == Architecture.AARCH64 ? 'Aarch64' : '') +
87116
(oss ? 'Oss' : '') +
88-
(base == DockerBase.UBI ? 'Ubi' : '') +
117+
(base == DockerBase.UBI ? 'Ubi' : (base == DockerBase.IRON_BANK ? 'IronBank' : '')) +
89118
suffix
90119
}
91120

92121
project.ext {
93122
dockerBuildContext = { Architecture architecture, boolean oss, DockerBase base, boolean local ->
94123
copySpec {
95-
into('bin') {
96-
from project.projectDir.toPath().resolve("src/docker/bin")
97-
}
98-
99-
into('config') {
100-
/*
101-
* The OSS and default distributions have different configurations, therefore we want to allow overriding the default configuration
102-
* from files in the 'oss' sub-directory. We don't want the 'oss' sub-directory to appear in the final build context, however.
103-
*/
104-
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
105-
from(project.projectDir.toPath().resolve("src/docker/config")) {
106-
exclude 'oss'
124+
final Map<String,String> varExpansions = expansions(architecture, oss, base, local)
125+
final Path projectDir = project.projectDir.toPath()
126+
127+
if (base == DockerBase.IRON_BANK) {
128+
into('scripts') {
129+
from projectDir.resolve("src/docker/bin")
130+
from(projectDir.resolve("src/docker/config")) {
131+
exclude '**/oss'
132+
}
133+
}
134+
from(projectDir.resolve("src/docker/iron_bank")) {
135+
expand(varExpansions)
107136
}
108-
if (oss) {
109-
// Overlay the config file
110-
from project.projectDir.toPath().resolve("src/docker/config/oss")
137+
} else {
138+
into('bin') {
139+
from projectDir.resolve("src/docker/bin")
140+
}
141+
142+
into('config') {
143+
// The OSS and default distribution can have different configuration, therefore we want to
144+
// allow overriding the default configuration by creating config files in oss or default
145+
// build-context sub-modules.
146+
duplicatesStrategy = DuplicatesStrategy.INCLUDE
147+
from projectDir.resolve("src/docker/config")
148+
if (oss) {
149+
from projectDir.resolve("src/docker/config/oss")
150+
}
111151
}
112152
}
113153

114154
from(project.projectDir.toPath().resolve("src/docker/Dockerfile")) {
115-
expand(expansions(architecture, oss, base, local))
155+
expand(varExpansions)
156+
filter SquashNewlinesFilter
116157
}
117158
}
118159
}
@@ -324,6 +365,8 @@ subprojects { Project subProject ->
324365

325366
final Architecture architecture = subProject.name.contains('aarch64-') ? Architecture.AARCH64 : Architecture.X64
326367
final boolean oss = subProject.name.contains('oss-')
368+
// We can ignore Iron Bank at the moment as we don't
369+
// build those images ourselves.
327370
final DockerBase base = subProject.name.contains('ubi-') ? DockerBase.UBI : DockerBase.CENTOS
328371

329372
final String arch = architecture == Architecture.AARCH64 ? '-aarch64' : ''
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import org.elasticsearch.gradle.Architecture
2+
import org.elasticsearch.gradle.DockerBase
3+
4+
apply plugin: 'base'
5+
6+
tasks.register("buildIronBankDockerBuildContext", Tar) {
7+
archiveExtension = 'tar.gz'
8+
compression = Compression.GZIP
9+
archiveClassifier = "docker-build-context"
10+
archiveBaseName = "elasticsearch-ironbank"
11+
// We always treat Iron Bank builds as local, because that is how they
12+
// are built
13+
with dockerBuildContext(Architecture.X64, false, DockerBase.IRON_BANK, true)
14+
}

distribution/docker/src/docker/Dockerfile

Lines changed: 52 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#
44
# Beginning of multi stage Dockerfile
55
################################################################################
6+
67
<% /*
78
This file is passed through Groovy's SimpleTemplateEngine, so dollars and backslashes
89
have to be escaped in order for them to appear in the final Dockerfile. You
@@ -13,13 +14,16 @@
1314
We use control-flow tags in this file to conditionally render the content. The
1415
layout/presentation here has been adjusted so that it looks reasonable when rendered,
1516
at the slight expense of how it looks here.
17+
18+
Note that this file is also filtered to squash together newlines, so we can
19+
add as many newlines here as necessary to improve legibility.
1620
*/ %>
21+
1722
<% if (docker_base == "ubi") { %>
1823
################################################################################
1924
# Build stage 0 `builder`:
2025
# Extract Elasticsearch artifact
2126
################################################################################
22-
2327
FROM ${base_image} AS builder
2428
2529
# Install required packages to extract the Elasticsearch distribution
@@ -44,7 +48,21 @@ RUN set -eux ; \\
4448
rm \${tini_bin}.sha256sum ; \\
4549
mv \${tini_bin} /bin/tini ; \\
4650
chmod +x /bin/tini
51+
52+
<% } else if (docker_base == 'iron_bank') { %>
53+
${build_args}
54+
55+
FROM ${base_image} AS builder
56+
57+
# `tini` is a tiny but valid init for containers. This is used to cleanly
58+
# control how ES and any child processes are shut down.
59+
COPY tini /bin/tini
60+
RUN chmod 0755 /bin/tini
61+
4762
<% } else { %>
63+
64+
<% /* CentOS builds are actaully a custom base image with a minimal set of dependencies */ %>
65+
4866
################################################################################
4967
# Stage 1. Build curl statically. Installing it from RPM on CentOS pulls in too
5068
# many dependencies.
@@ -194,6 +212,7 @@ COPY --from=curl /work/curl /rootfs/usr/bin/curl
194212
# Step 3. Fetch the Elasticsearch distribution and configure it for Docker
195213
################################################################################
196214
FROM ${base_image} AS builder
215+
197216
<% } %>
198217

199218
RUN mkdir /usr/share/elasticsearch
@@ -202,16 +221,17 @@ WORKDIR /usr/share/elasticsearch
202221
# Fetch the appropriate Elasticsearch distribution for this architecture
203222
${source_elasticsearch}
204223

205-
RUN tar zxf /opt/elasticsearch.tar.gz --strip-components=1
224+
RUN tar -zxf /opt/elasticsearch.tar.gz --strip-components=1
206225

207226
# Configure the distribution for Docker
208227
RUN sed -i -e 's/ES_DISTRIBUTION_TYPE=tar/ES_DISTRIBUTION_TYPE=docker/' /usr/share/elasticsearch/bin/elasticsearch-env
209-
RUN mkdir -p config config/jvm.options.d data logs
228+
RUN mkdir -p config config/jvm.options.d data logs plugins
210229
RUN chmod 0775 config config/jvm.options.d data logs plugins
211-
COPY config/elasticsearch.yml config/log4j2.properties config/
230+
COPY ${config_dir}/elasticsearch.yml ${config_dir}/log4j2.properties config/
212231
RUN chmod 0660 config/elasticsearch.yml config/log4j2.properties
213232

214-
<% if (docker_base == "ubi") { %>
233+
<% if (docker_base == "ubi" || docker_base == "iron_bank") { %>
234+
215235
################################################################################
216236
# Build stage 1 (the actual Elasticsearch image):
217237
#
@@ -221,6 +241,8 @@ RUN chmod 0660 config/elasticsearch.yml config/log4j2.properties
221241

222242
FROM ${base_image}
223243

244+
<% if (docker_base == "ubi") { %>
245+
224246
RUN for iter in {1..10}; do \\
225247
${package_manager} update --setopt=tsflags=nodocs -y && \\
226248
${package_manager} install --setopt=tsflags=nodocs -y \\
@@ -231,11 +253,26 @@ RUN for iter in {1..10}; do \\
231253
done; \\
232254
(exit \$exit_code)
233255

256+
%> } else { %>
257+
258+
<%
259+
/* Reviews of the Iron Bank Dockerfile said that they preferred simpler */
260+
/* scripting so this version doesn't have the retry loop featured above. */
261+
%>
262+
RUN ${package_manager} update --setopt=tsflags=nodocs -y && \\
263+
${package_manager} install --setopt=tsflags=nodocs -y \\
264+
nc shadow-utils zip unzip && \\
265+
${package_manager} clean all
266+
267+
<% } %>
268+
234269
RUN groupadd -g 1000 elasticsearch && \\
235270
adduser -u 1000 -g 1000 -G 0 -d /usr/share/elasticsearch elasticsearch && \\
236271
chmod 0775 /usr/share/elasticsearch && \\
237272
chown -R 1000:0 /usr/share/elasticsearch
273+
238274
<% } else { %>
275+
239276
################################################################################
240277
# Stage 4. Build the final image, using the rootfs above as the basis, and
241278
# copying in the Elasticsearch distribution
@@ -250,13 +287,15 @@ RUN addgroup -g 1000 elasticsearch && \\
250287
addgroup elasticsearch root && \\
251288
chmod 0775 /usr/share/elasticsearch && \\
252289
chgrp 0 /usr/share/elasticsearch
290+
253291
<% } %>
254292
255293
ENV ELASTIC_CONTAINER true
256294
257295
WORKDIR /usr/share/elasticsearch
258296
COPY --from=builder --chown=1000:0 /usr/share/elasticsearch /usr/share/elasticsearch
259-
<% if (docker_base == "ubi") { %>
297+
298+
<% if (docker_base == "ubi" || docker_base == "iron_bank") { %>
260299
COPY --from=builder --chown=0:0 /bin/tini /bin/tini
261300
<% } %>
262301
@@ -267,7 +306,7 @@ RUN ln -sf /etc/pki/ca-trust/extracted/java/cacerts /usr/share/elasticsearch/jdk
267306

268307
ENV PATH /usr/share/elasticsearch/bin:\$PATH
269308

270-
COPY bin/docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh
309+
COPY ${bin_dir}/docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh
271310

272311
# 1. The JDK's directories' permissions don't allow `java` to be executed under a different
273312
# group to the default. Fix this.
@@ -303,7 +342,8 @@ LABEL org.label-schema.build-date="${build_date}" \\
303342
org.opencontainers.image.url="https://www.elastic.co/products/elasticsearch" \\
304343
org.opencontainers.image.vendor="Elastic" \\
305344
org.opencontainers.image.version="${version}"
306-
<% if (docker_base == 'ubi') { %>
345+
346+
<% if (docker_base == 'ubi' || docker_base == 'iron_bank') { %>
307347
LABEL name="Elasticsearch" \\
308348
maintainer="[email protected]" \\
309349
vendor="Elastic" \\
@@ -324,6 +364,10 @@ ENTRYPOINT ["/bin/tini", "--", "/usr/local/bin/docker-entrypoint.sh"]
324364
# Dummy overridable parameter parsed by entrypoint
325365
CMD ["eswrapper"]
326366

367+
<% if (docker_base == 'iron_bank') { %>
368+
HEALTHCHECK --interval=10s --timeout=5s --start-period=1m --retries=5 CMD curl -I -f --max-time 5 http://localhost:9200 || exit 1
369+
<% } %>
370+
327371
################################################################################
328372
# End of multi-stage Dockerfile
329373
################################################################################
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Ignore any locally downloaded or dropped releases
2+
*.tar.gz
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
@Library('DCCSCR@master') _
2+
dccscrPipeline(version: '${version}')
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# Elasticsearch
2+
3+
**Elasticsearch** is a distributed, RESTful search and analytics engine capable of
4+
solving a growing number of use cases. As the heart of the Elastic Stack, it
5+
centrally stores your data so you can discover the expected and uncover the
6+
unexpected.
7+
8+
For more information about Elasticsearch, please visit
9+
https://www.elastic.co/products/elasticsearch.
10+
11+
### Installation instructions
12+
13+
Please follow the documentation on [how to install Elasticsearch with Docker](https://www.elastic.co/guide/en/elasticsearch/reference/current/docker.html).
14+
15+
### Where to file issues and PRs
16+
17+
- [Issues](https://github.com/elastic/elasticsearch/issues)
18+
- [PRs](https://github.com/elastic/elasticsearch/pulls)
19+
20+
### Where to get help
21+
22+
- [Elasticsearch Discuss Forums](https://discuss.elastic.co/c/elasticsearch)
23+
- [Elasticsearch Documentation](https://www.elastic.co/guide/en/elasticsearch/reference/master/index.html)
24+
25+
### Still need help?
26+
27+
You can learn more about the Elastic Community and also understand how to get more help
28+
visiting [Elastic Community](https://www.elastic.co/community).
29+
30+
31+
This software is governed by the [Elastic
32+
License](https://github.com/elastic/elasticsearch/blob/${major_minor_version}/licenses/ELASTIC-LICENSE.txt),
33+
and includes the full set of [free
34+
features](https://www.elastic.co/subscriptions).
35+
36+
View the detailed release notes
37+
[here](https://www.elastic.co/guide/en/elasticsearch/reference/${major_minor_version}/es-release-notes.html).
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"resources": [
3+
{
4+
"url": "https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-${version}-linux-x86_64.tar.gz",
5+
"filename": "elasticsearch-${version}-linux-x86_64.tar.gz",
6+
"validation": {
7+
"type": "sha512",
8+
"value": "<insert hash here>"
9+
}
10+
},
11+
{
12+
"url": "https://github.com/krallin/tini/releases/download/v0.19.0/tini-amd64",
13+
"filename": "tini",
14+
"validation": {
15+
"type": "sha256",
16+
"value": "93dcc18adc78c65a028a84799ecf8ad40c936fdfc5f2a57b1acda5a8117fa82c"
17+
}
18+
}
19+
]
20+
}

0 commit comments

Comments
 (0)