98 lines
		
	
	
		
			No EOL
		
	
	
		
			5.8 KiB
		
	
	
	
		
			Text
		
	
	
	
	
	
			
		
		
	
	
			98 lines
		
	
	
		
			No EOL
		
	
	
		
			5.8 KiB
		
	
	
	
		
			Text
		
	
	
	
	
	
<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> |