How to get into a Docker Container

I mostly have a Vapor API set up correctly by deploying it with a Dockerfile, as shown in these instructions

I’m doing a hello world example and can hit the endpoints that are unprotected properly, but I have an endpoint /todos that queries a Postgres database.

The table isn’t created in the database because I haven’t run the migrations (the default code doesn’t do that, yes I can add it and redeploy, but I was wondering how to run the command manually).

Typically shown here, I can run vapor run migrate, but I can’t figure out how fly.io has connected the API and the database to the VM (or remote builder?). When I ssh into the VM, I don’t even have a docker command??

Running fly ssh console I’m in the running Ubuntu VM, but when I try to just run docker -h I get

/bin/sh: 1: docker: not found

Shouldn’t the VM be running docker, to be able to run my API?

Hey, so flyctl only uses Docker to package your app into an image. Then it’s converted to a real VM - we don’t use Docker at all on our servers.

You should be able to run your command directly in the VM once you login with fly ssh console.

Once you’ve setup Postgres, ensure DATABASE_URL is set on your app to point to your database. Then try running your command.

Also, for the future, add a release command to your fly.toml and to run on each deployment:

[deploy]
  release_command = "vapor run migrate"

That’s interesting! Thanks for clarifying how that works!

This doesn’t happen, I can’t run the command, vapor isn’t detected, somehow…?

The DATABASE_URL does point to the database properly, I added it to the secrets.

If I add this command to the fly.toml that means it’ll run with every update right?

Yes, as the docs suggest - release commands run after a build but before the build is deployed. If the command fails, deployment aborts.

vapor not being detected may just be an issue with your PATH. If you post your Dockerfile, someone here may be able to help.

Thanks for the help!
Here’s the Dockerfile

# ================================
# Build image
# ================================
FROM swift:5.6-focal as build

# Install OS updates and, if needed, sqlite3
RUN export DEBIAN_FRONTEND=noninteractive DEBCONF_NONINTERACTIVE_SEEN=true \
    && apt-get -q update \
    && apt-get -q dist-upgrade -y \
    && rm -rf /var/lib/apt/lists/*

# Set up a build area
WORKDIR /build

# First just resolve dependencies.
# This creates a cached layer that can be reused
# as long as your Package.swift/Package.resolved
# files do not change.
COPY ./Package.* ./
RUN swift package resolve

# Copy entire repo into container
COPY . .

# Build everything, with optimizations
RUN swift build -c release --static-swift-stdlib

# Switch to the staging area
WORKDIR /staging

# Copy main executable to staging area
RUN cp "$(swift build --package-path /build -c release --show-bin-path)/Run" ./

# Copy resources bundled by SPM to staging area
RUN find -L "$(swift build --package-path /build -c release --show-bin-path)/" -regex '.*\.resources$' -exec cp -Ra {} ./ \;

# Copy any resources from the public directory and views directory if the directories exist
# Ensure that by default, neither the directory nor any of its contents are writable.
RUN [ -d /build/Public ] && { mv /build/Public ./Public && chmod -R a-w ./Public; } || true
RUN [ -d /build/Resources ] && { mv /build/Resources ./Resources && chmod -R a-w ./Resources; } || true

# ================================
# Run image
# ================================
FROM ubuntu:focal

# Make sure all system packages are up to date, and install only essential packages.
RUN export DEBIAN_FRONTEND=noninteractive DEBCONF_NONINTERACTIVE_SEEN=true \
    && apt-get -q update \
    && apt-get -q dist-upgrade -y \
    && apt-get -q install -y \
      ca-certificates \
      tzdata \
# If your app or its dependencies import FoundationNetworking, also install `libcurl4`.
      # libcurl4 \
# If your app or its dependencies import FoundationXML, also install `libxml2`.
      # libxml2 \
    && rm -r /var/lib/apt/lists/*

# Create a vapor user and group with /app as its home directory
RUN useradd --user-group --create-home --system --skel /dev/null --home-dir /app vapor

# Switch to the new home directory
WORKDIR /app

# Copy built executable and any staged resources from builder
COPY --from=build --chown=vapor:vapor /staging /app

# Ensure all further commands run as the vapor user
USER vapor:vapor

# Let Docker bind to port 8080
EXPOSE 8080

# Start the Vapor service when the image is run, default to listening on 8080 in production environment
ENTRYPOINT ["./Run"]
CMD ["serve", "--env", "production", "--hostname", "0.0.0.0", "--port", "8080"]

I’m currently running on Ubuntu 20.04

You’ll need to find where the vapor executable is. You could try find . -name vapor.

I tried to run that command, but didn’t get anything back, I’ll keep looking around tomorrow and let you know if I have any issues

Thanks @jsierles !

I’ve learned Vapor isn’t actually an executable, adding this won’t actually work.

[deploy]
  release_command = "vapor run migrate"

But how Docker is used with fly basically answers my questions

The reason the migrations weren’t being created was because I didn’t use the right DATABASE_NAME