How to create a container image

Containers are a new runtime for our applications. Building a secure, fast and minimum-size image is essential. In this article, we’ll do it.

A Containerfile, or Dockerfile if you are using Docker, is a file that describes how to build our container. Using the correct labels and instructions is crucial to getting a precise and optimum run.

We’ll study the principal options to define a Containerfile. In addition, we’ll build a Golang application and run it on a container.

Principal commands

A Containerfile is a series of labels which indicates how to build and run the container. The following table shows the principal labels and their descriptions.

command description
FROM declares the image to use as base
LABEL metadata
MAINTAINER indicates the Author
RUN executes shell commands as new layer
EXPOSE indicates a port to expose
ENV environment variable
ADD copies files or folders from a local o remote source. It also unpacks .tar files
COPY copies files or folder from the working directory
USER specifies the username or UID that the container will use to run
ENTRYPOINT specifies the default command when the container is running. By default it is /bin/sh -c
CMD indicates the default params for the ENTRYPOINT instruction

Application

Build the image

The best way to understand the images is by building one.

I have a Golang application to test and show some features. The application can be found here: https://github.com/dbgjerez/golang-k8s-helm-helloworld

Our objective is to run the application on a container, so we have to build the application and the container.

It’s a good practice to build on a container, as the building process would be idempotent using always the same Containerfile.

I’ve used the following:

FROM golang:1.18-alpine

ENV APP_NAME=golang-k8s-helm-helloworld
ENV GIN_MODE=release
ENV PORT=8080
ENV WORKDIR=/go/src/app

WORKDIR $WORKDIR
COPY . .

RUN go get -d -v ./...
RUN go install -v ./...
RUN rm -rf $WORKDIR
EXPOSE $PORT

ENTRYPOINT $APP_NAME

In this case, I’ll use the same Containerfile to build and run the application. Definitely, I’ll copy the source code, build the application and subsequently delete the source code.

To build the image, I’ll use podman which is not the objective of this article, in any case, you can check how to use it here: Podman

podman build \
  -t b0rr3g0/golang-hello-world:v0.6 \
  .

Finally, I’ll have a result which also is called a container image.

Run the image

As we have our image on the local registry, we can run it easily. I’ll run it as a daemon, mapping the port 8080 and assign the name api-test with the following command:

podman run \
  -d \
  -p 8080:8080 \
  --name api-test \
  localhost/b0rr3g0/golang-hello-world:v0.6

No, I’ll check the response:

curl localhost:8080/api/v1/greetings
{"msg":"Hello world"}

And voilĂ … we have a portable application running.

References


See also