98 lines
5.8 KiB
Plaintext
98 lines
5.8 KiB
Plaintext
<p>Creating a Docker image isn’t particularly difficult, but I never do
|
||
it often enough to remember the incantations required. Yesterday I
|
||
needed a Docker image for running CI jobs on <a href="https://circleci.com/">Circle CI</a>.
|
||
There are some great pre-built images out there, but I couldn’t find
|
||
the combination of Java 17, Leiningen, and Node that I was looking
|
||
for. This is a quick guide to how to build your own image with the
|
||
tools <em>you</em> need.</p>
|
||
<h2 id="great-artists-steal">Great Artists Steal</h2>
|
||
<p>First off we want to find a suitable base image to start with. Docker
|
||
images are built in layers, so we can start with a solid foundation
|
||
pre-written by an expert and simply layer on the additional bits we
|
||
need. Circle CI has a great set of <a href="https://circleci.com/docs/2.0/circleci-images/">pre-built Docker
|
||
images</a> that take care of the heavy lifting.</p>
|
||
<p>Here we’ll use their <code>cimg/openjdk:17.0.1-node</code> image. This is a
|
||
variant of their <code>cimg/openjdk:17.0.1</code> image which already includes
|
||
Node. Two pieces already done for us!</p>
|
||
<p>Create a new <code>Dockerfile</code> and add the following:</p>
|
||
<pre><code>FROM cimg/openjdk:17.0.1-node
|
||
MAINTAINER Your Name <you@your.domain>
|
||
</code></pre><p>To layer on Leiningen, I cribbed the relevant incantations from <a href="https://hub.docker.com/_/clojure">the
|
||
official Clojure Docker images</a>. From that
|
||
page you can click on any of the <code>Dockerfile</code> links to see how they’re
|
||
defined and borrow what you need.</p>
|
||
<p>In my case, I simply grabbed these lines and appended them to my
|
||
<code>Dockerfile</code>:</p>
|
||
<pre><code>### INSTALL LEIN ###
|
||
ENV LEIN_VERSION=2.9.8
|
||
ENV LEIN_INSTALL=/usr/local/bin/
|
||
WORKDIR /tmp
|
||
# Download the whole repo as an archive
|
||
RUN set -eux; \
|
||
sudo apt-get update && \
|
||
sudo apt-get install -y gnupg wget && \
|
||
sudo rm -rf /var/lib/apt/lists/* && \
|
||
mkdir -p $LEIN_INSTALL && \
|
||
wget -q https://raw.githubusercontent.com/technomancy/leiningen/$LEIN_VERSION/bin/lein-pkg && \
|
||
echo "Comparing lein-pkg checksum ..." && \
|
||
sha256sum lein-pkg && \
|
||
echo "9952cba539cc6454c3b7385ebce57577087bf2b9001c3ab5c55d668d0aeff6e9 *lein-pkg" | sha256sum -c - && \
|
||
sudo mv lein-pkg $LEIN_INSTALL/lein && \
|
||
sudo chmod 0755 $LEIN_INSTALL/lein && \
|
||
export GNUPGHOME="$(mktemp -d)" && \
|
||
export FILENAME_EXT=jar && \
|
||
if printf '%s\n%s\n' "2.9.7" "$LEIN_VERSION" | sort -cV; then \
|
||
gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys 6A2D483DB59437EBB97D09B1040193357D0606ED; \
|
||
else \
|
||
gpg --batch --keyserver hkps://keyserver.ubuntu.com --recv-keys 20242BACBBE95ADA22D0AFD7808A33D379C806C3; \
|
||
FILENAME_EXT=zip; \
|
||
fi && \
|
||
wget -q https://github.com/technomancy/leiningen/releases/download/$LEIN_VERSION/leiningen-$LEIN_VERSION-standalone.$FILENAME_EXT && \
|
||
wget -q https://github.com/technomancy/leiningen/releases/download/$LEIN_VERSION/leiningen-$LEIN_VERSION-standalone.$FILENAME_EXT.asc && \
|
||
echo "Verifying file PGP signature..." && \
|
||
gpg --batch --verify leiningen-$LEIN_VERSION-standalone.$FILENAME_EXT.asc leiningen-$LEIN_VERSION-standalone.$FILENAME_EXT && \
|
||
gpgconf --kill all && \
|
||
rm -rf "$GNUPGHOME" leiningen-$LEIN_VERSION-standalone.$FILENAME_EXT.asc && \
|
||
sudo mkdir -p /usr/share/java && \
|
||
sudo mv leiningen-$LEIN_VERSION-standalone.$FILENAME_EXT /usr/share/java/leiningen-$LEIN_VERSION-standalone.jar && \
|
||
sudo apt-get purge -y --auto-remove gnupg wget
|
||
ENV PATH=$PATH:$LEIN_INSTALL
|
||
ENV LEIN_ROOT 1
|
||
</code></pre><p>I’m very glad I didn’t have to write all of that myself because I
|
||
would have been tempted to cut corners on the validation of the
|
||
Leiningen package contents and that wouldn’t have been good.</p>
|
||
<h2 id="building-the-image">Building the Image</h2>
|
||
<p>Now we have everything we need to build the image. Open a shell to
|
||
the location where you put the <code>Dockerfile</code> and run the following
|
||
command (making appropriate name substitutions for your Docker
|
||
organization and desired image name):</p>
|
||
<div class="highlight"><pre><code class="language-sh">docker build --tag collbox/clojure-ci .
|
||
</code></pre></div><p>Docker will pull the base image, layer on your changes, and create a
|
||
new local image.</p>
|
||
<p>If you’re ready to share that image with your coworkers or build
|
||
server, push it to Docker Hub with:</p>
|
||
<div class="highlight"><pre><code class="language-sh">docker push collbox/clojure-ci
|
||
</code></pre></div><p>By default the image will be private. If you haven’t added any
|
||
private information, you can make the image public and make it easy to
|
||
access without adding authentication. Do this by logging into <a href="https://hub.docker.com/">Docker
|
||
Hub</a>, clicking the image, “Settings”, and “Make public”.</p>
|
||
<h2 id="next-steps">Next Steps</h2>
|
||
<p>Now you’re ready to use your new Docker image from a project by simply
|
||
using the name we tagged the image with above (<code>collbox/clojure-ci</code>,
|
||
in this example).</p>
|
||
<p>Finally, why not version control your <code>Dockerfile</code> and add a
|
||
<code>Makefile</code> for next time you forget this process and need to update
|
||
the image?</p>
|
||
<div class="highlight"><pre><code class="language-sh">image<span style="color: #f92672;">=</span>collbox/clojure-ci
|
||
build:
|
||
docker build --tag <span style="color: #66d9ef;">$(</span>image<span style="color: #66d9ef;">)</span> .
|
||
push:
|
||
docker push <span style="color: #66d9ef;">$(</span>image<span style="color: #66d9ef;">)</span>
|
||
.PHONY: build push
|
||
</code></pre></div><p>Now you can rebuild the image with a simple <code>make build</code> or re-push it
|
||
with <code>make push</code>.</p>
|
||
<p>That’s all there is to it.</p>
|
||
<hr />
|
||
<p>If you want to see the code above fully
|
||
assembled, check out <a href="https://github.com/collbox/clojure-ci-docker">collbox/clojure-ci-docker on
|
||
GitHub</a>.</p> |