Developing and Testing Server-Side Swift with Docker and Vapor

Use Docker to develop and test your Vapor apps and learn to use Docker Compose to run different services, which include a database. By Natan Rolnik.

4.2 (5) · 3 Reviews

Download materials
Save for later
Share
You are currently viewing page 2 of 4 of this article. Click here to view the first page.

Creating the Development Dockerfile

To get started, create a file named development.Dockerfile in the project’s root directory, at the same level of Package.swift. Use either your preferred text editor or run touch development.Dockerfile in Terminal, as long as you’re in the correct location. Open the file and add the following content:

# 1
FROM swift:5.5
WORKDIR /app
COPY . .

# 2
RUN apt-get update && apt-get install libsqlite3-dev

# 3
RUN swift package clean
RUN swift build

# 4
RUN mkdir /app/bin
RUN mv `swift build --show-bin-path` /app/bin

# 5
EXPOSE 8080
ENTRYPOINT ./bin/debug/Run serve --env local --hostname 0.0.0.0

Let’s go over the instructions you just added:

  1. The starting point of a Dockerfile is to set the base image. In this case, you’ll use the official Swift 5.5 image. Then, you set the current directory to /app and copy the contents of the project into the image working directory you specified.
  2. As the app is currently using SQLite as a database, you’ll install libsqlite3-dev in the image. Later, you’ll replace this with PostgreSQL.
  3. Then, you clean the packages cache and compile the app with Swift. The default configuration of Swift’s build command is debug, so there’s no need to specify it unless you want to build for release.
  4. Then, you create a directory to store the built product, which is the binary app executable. Then, fetch the binary path from the build process and copy its contents to the newly created /app/bin folder.
  5. Finally, you’ll tell Docker to expose the 8080 port, the default port Vapor listens to, and define the entry point. In this case, it’s the serve command from the executable.
Note: The Dockerfile reference contains the documentation of all available Dockerfile commands. Refer to this page if you want to learn more about each command and its different options and forms.

Building the Image

After you save the Dockerfile, go back to Terminal and run the build command, which tells Docker to build your app image:

docker build . --file development.Dockerfile --tag til-app-dev

A few notes about this command:

  • The dot is the path where Docker looks for the Dockerfile. In this case, it’s the current directory.
  • The --file flag is necessary because a named Dockerfile is being used. If the name of the file were just Dockerfile, Docker would find it automatically without the flag.
  • The --tag flag tells Docker how to identify this image. This makes it easier for Docker to access it later, when it’s time to run it.

Once you run this command, Docker will start by pulling the base image. Then it will run all the instructions present in the Dockerfile to build the application image.

This should take a few minutes, and it’s easy to follow the progress by looking at the logs.

After the build command finishes, check the existing images. Run:

docker images

Alternatively, you can also open the Docker for Desktop application, and select the Images item in the left menu. The image will appear in a list, like the screenshot below shows:

The app image in Docker for Desktop.

The app image in Docker for Desktop

The app image in Docker for Desktop.

Running the Image

After you confirm the app image is present, run it using the following command:

docker run \
  --name til-app-dev \
  --interactive --tty \
  --publish 8080:8080 \
  til-app-dev

This command is long so here’s a break down of all it’s doing:

  1. Creating a new container based on an image you specify.
  2. Passing a name to identify this new container. In this case, til-app-dev.
  3. Reading the app logs and stopping the container, passing --interactive and --tty.
  4. Publishing the 8080 port from the container and mapping it to the 8080 port on your computer.
  5. Passing the name of the image you built in the previous section.
Note: The name of the image doesn’t need to match the name of the container. Images and containers are two different Docker concepts.

Docker creates and runs the new container. You’ll see the logs in Terminal stating that the server started on the 8080 port. Since you published the port to the host machine, now visit http://0.0.0.0:8080 or http://localhost:8080 in your browser and you’ll see the home page of the TIL app. How cool is that? Your app is running on a Linux image within your Mac!

To stop the container, stop the process using the shortcut Control-C. This won’t delete the container; you can start it again later on.

If you try to refresh the page in your browser, you’ll see that now it fails. This error occurs because you stopped the container. Next, you’ll learn how to start a stopped container.

Starting and Attaching to a Container

To start a stopped container, use start. Run the container you want by passing its name, as follows:

docker start til-app-dev

You’ll notice that Docker returned immediately after starting the container without displaying any logs. That’s because Docker does only what you tell it to do. The start command only starts the container in the background and doesn’t attach to the container’s standard input, output and error streams. If you run docker container ls, you’ll see that the container is running. Alternatively, you could also open the Docker for Desktop app or refresh the browser to check that it’s running.

To see the container logs, run the attach command. It will connect your terminal to the running container:

docker attach til-app-dev

Now, you’ll notice that the command didn’t return immediately and that your Terminal is attached to the app. However, no logs are available because you started the container before attaching to it. Refreshing the browser is enough to trigger a new request to the app, which will print some more logs to the console.

Instead of running the start and attach commands separately, use the start command and pass the --attach --interactive flags, like so:

docker start til-app-dev --attach --interactive

Now that you are acquainted with the basics, it’s time to hook up TIL with a production-scale database, like Postgres.