Giter Site home page Giter Site logo

docker-practice's Introduction

Docker Practice: Running Go app with Docker

Step by step on how to use docker to build and run Go app.

Dockerfile

It is used to create Docker Image

  1. Create a file named Dockerfile

    A simple Dockerfile for a go app could be like this:

    # Choose golang image we want to use
    FROM golang:1.18-bullseye
    # Set current work directory
    WORKDIR /app
    # For simplicity, copy all the files inside the project folder
    # To the work dir
    COPY . .
    # Build the go app
    RUN CGO_ENABLED=0 GOOS=linux go build main.go -o myapp .
    # Run the binary
    CMD ["./myapp"]

    Note: go build will automatically download the project dependencies (go mod) so no need to manually download them

  2. Build image docker build -t myapp . myapp is the docker image name/tag

  3. Verify build with docker images

Running Docker

To create container from the created image, run docker run -p 8080:8081 -it myapp

-p 8080:8081 - This exposes our application which is running on port 8081 within our container on http://localhost:8080 on our host/local machine.

Multi-Stage Build

With multi-stage builds, Dockerfile can be splitted into multiple sections. Each stage has its own FROM statement. So it can involve multiple image in the builds.

Stages are built sequentially and can reference their predecessors, so the output of one layer can be copied into the next layer.

# syntax=docker/dockerfile:1.4

#### First stage
FROM golang:1.18-bullseye AS builder
WORKDIR /app
COPY main.go .
RUN CGO_ENABLED=0 GOOS=linux go build main.go -o myapp .

#### Second stage
FROM alpine:latest  
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=builder /app/myapp .
ENTRYPOINT ["./app"] 

builder is alias for the first stage. This can be referenced in the second stage to copy the build file to a new target environment

Docker Compose

Rather than manually call docker run, we can simplify it by using Makefile or Docker Compose. With a single command, can spin everything up or tear it all down.

Main purpose of Docker Compose itself is for running multiple containers as a single service.

  1. Create file docker-compose.yml
  2. Define version and services
  3. Under services, create service with custom name. In this project we use app
  4. Build can have context. It's enough to specify just . to automatically use current work directory and default Dockerfile name build: .
  5. To run/stop container:
docker compose up   # start container
docker compose stop # stop container
docker compose down # stop and remove container

# To run it (interactive) command, use 
docker compose run {service name} {shell-command} 
# example 
docker compose run myapp uname

Set Timezone

  1. Declare env TZ=Asia/Jakarta on docker file. Some image might require tzdata package to be installed
  2. On Docker run with arg -e TZ=Asia/Jakarta or
  3. Mapping timezone and localtime from the docker host volume:
docker run -v /etc/timezone:/etc/timezone:ro \
    -v /etc/localtime:/etc/localtime:ro -it  \
    docker-practice-api:latest-dev

When using docker compose:

volumes:
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro

Note: mapping /etc/timezone might not work on macOS

Exposing and Publishing Ports

In Dockerfile, exposing ports does not bind the port to the host's network interfaces. The port won't be accessible outside the container. This only is a simple way of checking which ports the software inside a container is listening on. To check run docker ps

Publishing ports make it accessible from outside the container with the -p flag for the docker run command. docker run -d -p 80 myapp make the host os can access http://localhost

see Reference for more information.

Entry Point

It is intruction used to specify the executable which should run when a container is started from a Docker image.

In Dockerfile:

COPY --from=builder /app/myapp /
ENTRYPOINT [ "/myapp" ]
# or
CMD ["/myapp"]

If entry point is not specified in Docker file, it will throw error docker: Error response from daemon: No command specified. So --entrypoint parameter must be specified when running docker:

docker run --entrypoint [new_command] [docker_image] [optional:value]

# Example:
docker run -it --entrypoint /myapp docker-practice
docker run -it --entrypoint /bin/bash docker-practice

In docker-compose specify inside service:

api:
    build: .
    entrypoint: "/myapp"
    ...

It's better to specify entry point in docker file, so when there's change of the entrypoint or executable file name only the docker file needs to be updated

Rebuilding Image

Any changes to source code, require to rebuild the image to apply the changes by executing one of the commands.

docker build
docker compose build 
docker compose up --build # build and run 

๐Ÿ’ก Tips: Build Image Faster

One of the problem of building go app using docker is every time go build run, it would redownload all the dependencies and slow down the build process.

The solution is using Docker Build Kit. It enables higher performance docker builds and caching possibility to decrease build times and increase productivity for free.

  1. Add # syntax=docker/dockerfile:1.4 in the first line of docker file
  2. Put env var DOCKER_BUILDKIT=1 before calling docker build or docker compose --build

    To apply the var globally put it in our shell profile (.bashrc or .zshrc): export DOCKER_BUILDKIT=1

  3. Use statement RUN --mount=type=cache,mode=0755,target={target folder} {buildcommand}

See Reference for the detail

Go Fiber Prefork

When running app with go fiber prefork enabled, the app will stop by displaying exit status 1. To encounter this issue, add parameter --pid=host inside docker run as referenced here.

docker run -p 8080:8081 --pid=host -it myapp

For docker compose, specify it under the app service.

service:
    app:
        ...
        pid: "host"

TODO

  • Add External App dependency (f.e Database) so it can be deployed as single service via Docker Compose
  • Use Volume for data persistance
  • Add binary compression to reduce docker image size

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.