Deploy rocket application to docker

I wanted help with writing a Dockerfile for a simple hello world rocket application. I have written one which runs the rust executable generated from cargo build. It said that Rocket has launched... but when I go to localhost:8000 (or any endpoint I provide it) it said the sit cannot be reached

Are you exposing the corresponding port on your docker container? For example, if your Rocket application is listening on port 8000, you also need to expose port 8000 on the container in order to be able to access it.

You should be able to add the following line to your Dockerfile before you start the app via CMD or RUN:

EXPOSE 8000

My own site is using the same setup (Rocket application inside a Docker container) with a reverse proxy in front of it (and other containers). A complete example file might look like the following (note that here I build the binary inside of the first container, labelled via AS builder):

FROM ekidd/rust-musl-builder:latest AS builder
# Update ubuntu package repositories
RUN sudo apt-get update
# Copy in code and ensure correct permissions
COPY src src
RUN sudo chown -R rust:rust /home/rust/src/app
COPY Cargo.lock .
RUN sudo chown rust:rust /home/rust/src/Cargo.lock
COPY Cargo.toml .
RUN sudo chown rust:rust /home/rust/src/Cargo.toml
COPY Rocket.toml .
RUN sudo chown rust:rust /home/rust/src/Rocket.toml
COPY rust-toolchain .
RUN sudo chown rust:rust /home/rust/src/rust-toolchain
# Ensure nightly toolchain installed for musl target
RUN /bin/bash -c "rustup toolchain install $(cat rust-toolchain)"
RUN /bin/bash -c "rustup target add x86_64-unknown-linux-musl --toolchain $(cat rust-toolchain)"
# Build
RUN /bin/bash -c "cargo +$(cat rust-toolchain) build --release --target x86_64-unknown-linux-musl"


FROM alpine:3.9.4 AS app
# Set working directory
WORKDIR /usr/src/app
# Copy in statically linked binary from builder stage
COPY --from=builder /home/rust/src/target/x86_64-unknown-linux-musl/release/your_app_name /usr/local/bin
# Expose port for server
EXPOSE 8000
# Run entrypoint script
CMD your_app_name

This might be overkill for you (or me for that matter), but it works and is how I deploy via Gitlab CI (albeit with a few extra steps I omitted here since they're site specific).

Yes, I have exposed the port. If it helps, I can't ctrl+c to stop the docker run? I have to close the shell

This is my Dockerfile:

FROM rust:1.37 as builder

WORKDIR "/project/user-app"

RUN rustup default nightly \
 && rustup update
 
COPY filename.sh .

# copy dependency files 
COPY Cargo.toml Cargo.toml

# get user application dependencies
RUN cargo fetch 

COPY Rocket.toml Rocket.toml

#copy user code
COPY src ./src

ENV ROCKET_ENV=production

# build for release
RUN cargo build --release

FROM rust:1.37-slim-stretch

RUN useradd rust

WORKDIR "/project/user-app"

# get files and built binary from previous image
COPY --from=builder /project/user-app/filename.sh /project/user-app/Cargo.toml /project/user-app/Rocket.toml /project/user-app/target/release/ ./

RUN chmod +x filename.sh \
 && chown rust:rust $(./filename.sh)

USER rust

EXPOSE 8000

CMD ["bash", "-c", "./$(./filename.sh)"]

filename.sh is just a script I wrote to get the name of the built binary (since I want users to be able to call it whatever they want)

How are you currently running the container? If you're using docker run ... could you try instead using docker run -d ... - this should run the container as a background process.

If you then run docker ps -a you should be able to see a list of containers and which ports are being exposed/forwarded to. You should see something like 0.0.0.0:8000->8000/tcp for your container. If you don't see that, could you post the output line of docker ps -a relating to your container here?

The port I'm getting is 8000/tcp. Does that mean the port is not being forwarded correctly?

Yes, currently you are exposing the port on the container but not telling your host to forward traffic to it. If you add the following flag to your docker run command it should work: -p 8000:8000. Your command should end up being something like docker run -d -p 8000:8000 ....

2 Likes

Thank you! But is there a way to specify this inside the Dockerfile?

Sorry if that's a silly question...

Per the documentation here: https://docs.docker.com/engine/reference/builder/#expose I don't believe you can do that from inside the Dockerfile:

The EXPOSE instruction does not actually publish the port. It functions as a type of documentation between the person who builds the image and the person who runs the container, about which ports are intended to be published. To actually publish the port when running the container, use the -p flag on docker run to publish and map one or more ports, or the -P flag to publish all exposed ports and map them to high-order ports.

I'm not an expert with Docker though, so I'd be happy to be corrected.

EXPOSE only exposes the port to the world, it doesn't actually map it to the world, and it by design doesn't allow a forced mapping in the docker image as that can be used for malicious reasons. I'd recommend docker-compose, it comes with docker and is basically a 'compose' script like the docker script for managing multiple docker images and how to map them to each and the world.