Docker is an open-source tool that helps developers to create, deploy, and run applications by using containers. Docker makes it easy to package and ship programs quickly.
Docker Compose is a container orchestration tool that allows you to run multiple containers at the same time. It allows developers to manage and extend a container simultaneously as per requirement.
Go is an open-source programming language used to build a simple, reliable, and efficient software application. It provides some build-in tools that allow you to safely use memory, manage objects, collect garbage, and provide static typing along with concurrency.
In this tutorial, we will create a simple Go application and deploy it with a Docker container. We will also use Nginx as a reverse proxy to bind the domain name with Go application.
Requirements
- A server running Ubuntu 20.04
- A valid domain name pointed with your server IP. In this tutorial, we will use the app.example.com domain.
- A root password is configured on your server
Install Docker and Docker Compose
First, you will need to install Docker and Docker compose to your server. First, install all the required dependencies with the following command:
apt-get install apt-transport-https ca-certificates curl software-properties-common gnupg2 -y
Once all the dependencies are installed, import the GPG key and add the Docker repository with the following command:
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add - add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
Next, install Docker and Docker Compose package with the following command:
apt-get install docker-ce docker-compose -y
Once both packages are installed, verify the status of the Docker with the following command:
systemctl status docker
You should get the following output:
- docker.service – Docker Application Container Engine
Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset: enabled) Active: active (running) since Thu 2021-01-28 02:12:22 UTC; 3min 2s ago
TriggeredBy: ● docker.socket
Docs: https://docs.docker.com Main PID: 11651 (dockerd) Tasks: 12 Memory: 462.1M CGroup: /system.slice/docker.service └─11651 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock Jan 28 02:12:22 ubuntu2004 dockerd[11651]: time="2021-01-28T02:12:22.488276730Z" level=info msg="Loading containers: done." Jan 28 02:12:22 ubuntu2004 dockerd[11651]: time="2021-01-28T02:12:22.520737199Z" level=info msg="Docker daemon" commit=8891c58 graphdriver(s)=> Jan 28 02:12:22 ubuntu2004 dockerd[11651]: time="2021-01-28T02:12:22.520927136Z" level=info msg="Daemon has completed initialization" Jan 28 02:12:22 ubuntu2004 systemd[1]: Started Docker Application Container Engine. Jan 28 02:12:22 ubuntu2004 dockerd[11651]: time="2021-01-28T02:12:22.571192985Z" level=info msg="API listen on /run/docker.sock" Jan 28 02:14:01 ubuntu2004 dockerd[11651]: time="2021-01-28T02:14:01.042676161Z" level=info msg="ignoring event" container=706c62976be8467ff71> Jan 28 02:14:01 ubuntu2004 dockerd[11651]: time="2021-01-28T02:14:01.709602994Z" level=info msg="Layer sha256:5f05406a7838ba878004dc19a5202f6d> Jan 28 02:14:03 ubuntu2004 dockerd[11651]: time="2021-01-28T02:14:03.931281935Z" level=info msg="ignoring event" container=2ee59dc155782d2c587> Jan 28 02:14:04 ubuntu2004 dockerd[11651]: time="2021-01-28T02:14:04.536259329Z" level=info msg="Layer sha256:fab63bfda26955d7ac58d0e2916e0271> lines 1-21/21 (END)
To verify the Docker version, run the following command:
docker -v Output: Docker version 20.10.2, build 2291f61 To verify the Docker Compose version, run the following command: docker-compose -v
Output:
docker-compose version 1.25.0, build unknown
Create a Simple Go Application
First, create a directory for your project with the following command:
mkdir ~/myproject Next, create a simple Go application with the following command: nano ~/myproject/main.go
Add the following lines:
package main
import ( "fmt" "html" "log" "net/http" ) func main() { http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "This application is hosted with Docker, %q", html.EscapeString(r.URL.Path)) })
http.HandleFunc("/hi", func(w http.ResponseWriter, r *http.Request){ fmt.Fprintf(w, "Hi") }) log.Fatal(http.ListenAndServe(":80", nil)) }
Save and close the file when you are finished. The above application will listen on port 80 and print the message “This application is hosted with Docker /” after successful execution.
-
Create a Docker Compose File for Nginx
Next, you will need to create a Docker Compose file for Nginx. This will download the Nginx-proxy image and create an Nginx proxy container for the Go application.
You can create a Docker Compose file with the following command:
nano nginx-proxy-compose.yaml
Add the following lines:
version: '2' services: nginx-proxy: restart: always image: jwilder/nginx-proxy ports: - "80:80" volumes: - "/etc/nginx/vhost.d" - "/usr/share/nginx/html" - "/var/run/docker.sock:/tmp/docker.sock:ro"
Save and close the file then change the directory to your project directory and build the Nginx proxy container with the following command:
cd ~/myproject docker-compose -f nginx-proxy-compose.yaml up -d You should get the following output: Creating network "myproject_default" with the default driver Pulling nginx-proxy (jwilder/nginx-proxy:)... latest: Pulling from jwilder/nginx-proxy bb79b6b2107f: Pull complete 111447d5894d: Pull complete a95689b8e6cb: Pull complete 1a0022e444c2: Pull complete 32b7488a3833: Pull complete c45cf71bc68c: Pull complete 00d28348da58: Pull complete 190f1720abb7: Pull complete a99149d671c6: Pull complete c7e9f170fd7c: Pull complete accc49186289: Pull complete e67d699eb6f8: Pull complete Digest: sha256:695db064e3c07ed052ea887b853ffba07e8f0fbe96dc01aa350a0d202746926b Status: Downloaded newer image for jwilder/nginx-proxy:latest Creating myproject_nginx-proxy_1 ... done
-
Create a Dockerfile
Next, you will need to create a Dockerfile to download Golang and Alpine image. You can create it with the following command:
nano ~/myproject/Dockerfile
Add the following lines:
FROM golang:alpine AS build RUN apk --no-cache add gcc g++ make git WORKDIR /go/src/app COPY . . RUN go get ./... RUN GOOS=linux go build -ldflags="-s -w" -o ./bin/web-app ./main.go FROM alpine:3.9 WORKDIR /usr/bin COPY --from=build /go/src/app/bin /go/bin EXPOSE 80 ENTRYPOINT /go/bin/web-app --port 80
Save and close the file when you are finished.
-
Create and Run Docker Compose File for Golang App
Next, you will need to create a Docker Compose file to create a container from the Docker image which you have downloaded in previous step.
You can create it with the following command:
nano ~/myproject/go-app-compose.yaml
Add the following lines:
version: '2' services: go-web-app: restart: always build: dockerfile: Dockerfile context: . environment: - VIRTUAL_HOST=app.example.com
Save and close the file then change the directory to your project and run your Go application with the following command:
cd ~/myproject docker-compose -f go-app-compose.yaml up -d
You should get the following output:
Step 1/11 : FROM golang:alpine AS build alpine: Pulling from library/golang 596ba82af5aa: Pull complete 344f2904b0c6: Pull complete d3bda26d9fa1: Pull complete 24e1a14bb4a2: Pull complete f0b175b107d5: Pull complete Digest: sha256:07ec52ea1063aa6ca02034af5805aaae77d3d4144cced4e95f09d62a6d8ddf0a Status: Downloaded newer image for golang:alpine Successfully built 3b45ca7113a5 Successfully tagged myproject_go-web-app:latest
You can verify all Docker images using the command below:
docker images
You should see the following output:
REPOSITORY TAG IMAGE ID CREATED SIZE myproject_go-web-app latest 3b45ca7113a5 24 seconds ago 10.1MB <none> <none> e7352aa7a608 27 seconds ago 511MB golang alpine 6af5835b113c 8 days ago 300MB jwilder/nginx-proxy latest 509ff2fb81dd 2 months ago 165MB alpine 3.9 78a2ce922f86 9 months ago 5.55MB
You can also verify all containers with the following command:
docker ps
You should see the following output:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES bfa0bdb20b0c myproject_go-web-app "/bin/sh -c '/go/bin…" 40 seconds ago Up 38 seconds 80/tcp myproject_go-web-app_1 3a021f37e3a7 jwilder/nginx-proxy "/app/docker-entrypo…" 3 minutes ago Up 3 minutes 0.0.0.0:80->80/tcp myproject_nginx-proxy_1
-
Access the Go Application
At this point, your Go application has been deployed. It listens on port 80 and binds to the domain app.example.com. You can access it using the URL http://app.example.com. You should see your Go application in the following page:
-
Conclusion
Congratulations! you have successfully deployed a Go application with Docker on Ubuntu 20.04. I hope you have now enough knowledge to deploy your own app in a containerized environment.
Also Read: How To Deploy Flask Application With Docker On Ubuntu?