Now everything is ready to build and pack the microservice to an image. To do this, add the Dockerfile file to the folder with the microservice and add the following lines to it:
FROM rust:nightly
RUN USER=root cargo new --bin users-microservice
WORKDIR /users-microservice
COPY ./Cargo.toml ./Cargo.toml
RUN cargo build
RUN rm src/*.rs
COPY ./src ./src
COPY ./diesel.toml ./diesel.toml
RUN rm ./target/debug/deps/users_microservice*
RUN cargo build
CMD ["./target/debug/users-microservice"]
EXPOSE 8000
We created the image based on the rust:nightly images that we created earlier in this chapter. We set it using the FROM command. The next line creates a new crate:
RUN USER=root cargo new --bin users-microservice
You might ask why we did that and didn't use an existing crate. That's because we will reproduce the creation of the crate inside the container to build dependencies first, to avoid the lengthy process of rebuilding them, when you would add any tiny change to the source code of the microservice. This approach will save you a lot of time. Copy Cargo.toml to the image and build all of the dependencies without the sources of the microservice (since we have not copied them yet):
WORKDIR /users-microservice
COPY ./Cargo.toml ./Cargo.toml
RUN cargo build
The next set of commands adds sources and the diesel.toml file to the image, removes previous build results, and builds the crate again with the new sources:
RUN rm src/*.rs
COPY ./src ./src
COPY ./diesel.toml ./diesel.toml
RUN rm ./target/debug/deps/users_microservice*
RUN cargo build
At this moment, the image contains a binary of a microservice that we can use as a starting command for containers:
CMD ["./target/debug/users-microservice"]
By default, a container doesn't open a port and you can't connect to it with another container or forward the port of a container to a local port. Since our microservice starts at port 8000, we have to expose it using the following command:
EXPOSE 8000
The image is ready to build and run a container. Let's do it.