Swift with Docker

Eugen Fedchenko
2 min readJun 11, 2018

--

I like server-side development, I like Swift, so it’s obvious that I’m interested in server-side Swift. But modern backend development isn’t possible without Docker (at least extremely uncomfotable).

Fortunately we are able to run Swift applications inside Docker container. Regular Dockerfile for Swift commonly looks like:

FROM swift:latest
ADD . /app
WORKDIR /app
RUN swift package resolve
RUN swift build --configuration release
EXPOSE 8080
ENTRYPOINT .build/release/SwiftDocker

It’s simple and obvious sample. But unfortunatelly the result container will be quite big, about 1.35G. This makes it difficult to work with image. At least I have only 250G on my Mac, so I have to handle this problem.

Docker supports multistage images. When you build something in one image and copy it into another. It gives possibility to build application inside full image but run it using only minimal image: OS + necessary libraries.

I always use this technics with my Golang application. Go compiler is able to create one executable file that contains all dependencies. Unfortunately, the Swift compiler has some issues with static linking the standard library and Foundation.

I found possible solution in this post A Minimal Swift Docker Image.

But directly solution from article hadn’t worked for me. So I’ve modified it. The main idea is using ldd to determine which shared libraries binary needs and compress them into archive.

#!/bin/bash
BIN="$1"
OUTPUT_TAR="${2:-swift_libs.tar.gz}"
TAR_FLAGS="hczvf"
DEPS=$(ldd $BIN | awk 'BEGIN{ORS=" "}$1\
~/^\//{print $1}$3~/^\//{print $3}'\
| sed 's/,$/\n/')
tar $TAR_FLAGS $OUTPUT_TAR $DEPS

The script from post above I didn’t make any changes, it just works.

And Dockerfile:

FROM swift:latestADD . /app
WORKDIR /app
RUN swift package resolve
RUN swift build --configuration release
COPY pkg-swift-deps.sh /usr/bin/pkg-swift-deps
RUN chmod +x /usr/bin/pkg-swift-deps
RUN pkg-swift-deps .build/release/SwiftDocker
FROM busybox:glibcCOPY --from=0 app/swift_libs.tar.gz /tmp/swift_libs.tar.gz
COPY --from=0 app/.build/release/SwiftDocker /usr/bin/
RUN tar -xzvf /tmp/swift_libs.tar.gz && \
rm -rf /tmp/*
CMD ["SwiftDocker"]

I guess, it’s clear. Probably except line

RUN chmod +x /usr/bin/pkg-swift-deps

Without this line Docker couldn’t run script, we have to point that it’s executable.

The final image is only 62.4MB. It’s a big win comparing with 1.35G!

The full project you can find on the Github.

I’m planning to continue experiments with server-side Swift and it’s a good start point.

Thank for Lars-Jørgen Kristiansen and Jeremy Jacobson I used theirs article for creating mine )

--

--