今晚,我想來點 Golang Server 加 PostgreSQL - Docker-Compose 篇

本文章同時發佈於:

文章為自己的經驗與夥伴整理的內容,設計沒有標準答案,如有可以改進的地方,請告訴我,我會盡我所能的修改,謝謝大家~

大家好,繼昨天DAY03Docker 的介紹後,接下來要介紹如何 Docker-Compose 來管理多個環境。

為何需要 Docker-Compose ?

還記得昨天的 Service 架構圖嗎?裡頭除了 PostgreSQL 以外還有 Golang Server,我們一樣可以透過 Docker 來對 Golang Server 的環境做封裝,以提供所有的開發人員都在同一個環境開發。

而當有一堆 Docker 時,我們希望有個方法可以把

Docker 的啟動方法、環境變數、容器間的關係寫成成配置文件,並利用此文件簡單的啟動所有容器

這時 Docker-Compose 就出馬了!

統一 Golang 環境的好處

可以避免不同人員裝了不同版本的 Golang,導致程式運行狀況有所差異的問題。不同開發人員也不用為了要安裝相同的 Golang 而飽受更新降版地獄。

你可能會問,什麼時候會需要這麼多版本的 Golang?

答案是當管理一堆專案時。

以前我管理一堆 Python 專案時,Python2 跟 Python3 的歷史淵源導致套件版本相依問題非常嚴重,導致我與夥伴們是三天一小亂,五天直接重灌,而後來改用 Docker 之後這個問題就完美的解決了。

雖然 Golang 目前版本差異不大應該不太會有大問題,但未來怎麼樣誰知道呢?你還是可以試看看這個不錯的選擇。

安裝 Docker-Compose

在官網上都有把安裝的教學寫得很清楚了,這篇文章就關注實作而不是安裝了。

Docker-Compose 檔案配置(Example code)

製作 Golang Server 的 Dockerfile

# Golang Server's Dockerfile
FROM golang:1.14.6-alpine

RUN apk add --no-cache git

RUN go get github.com/lib/pq
  • FROM golang:1.14.6-alpine: 選用 Golang 環境的版本
  • RUN apk add --no-cache git: 因為 Golang 下載模組需要 Git,我們透過 apk 來安裝
  • RUN go get github.com/lib/pq: 安裝 Golang 連線 PostgreSQL 的模組

製作docker-compose.yaml檔,

version: "3.5"

services:
  server:
    build:
      context: ./docker/golang
      dockerfile: Dockerfile
    working_dir: /server
    volumes:
      - .:/server
    ports:
      - "5000:5000"
    depends_on:
      - db
    entrypoint: go run main.go
    restart: always
  db:
    image: postgres:12.4-alpine
    ports:
      - "5432:5432"
    environment:
      - POSTGRES_USER=user
      - POSTGRES_PASSWORD=mysecretpassword
      - PGDATA=/var/lib/postgresql/data/pgdata
    restart: always
  • version: "3.5": 選定 docker-compose 的版本,每個版本提供的 API 方法有所差異。
  • services: 此欄位底下會有所有的容器,以下分別有serverdb兩個 容器。
  • build: 說明此容器要使用特定 Dockerfile 來 build,context為檔案目錄,dockerfile為 Dockerfile 的名字。
  • working_dir: 指定 docker 啟動時所在的目錄,如果目錄不存在會自動創建一個。
  • volumes: 將本機檔案掛載至 docker 內部,本機檔案更新時 docker 內部的掛載檔案也會更新。
  • ports: 將本機的 port 做 mapping 與 docker 內部的 poart。
  • depends_on: 說明 a 容器與 b 容器有相關,會等到 b 容器啟動完畢後,再啟動 a 容器。
  • entrypoint: 指定 docker 啟動時的預設指令。
  • restart: 當容器不正常關閉時,會重新啟動容器。
  • image: 如果不使用 Dockerfile 來建立容器,你可以直接使用 docker image 來啟動容器。
  • environment: 指定容器內的環境變數。

可以看到docker-compose.yaml很方便,把昨天文章中要輸入的environment變數都變成了設定檔。

透過working_dir配合volumes我們可以把當下目錄(即是.目錄)的檔案掛載至 docker 中,這可以使我們開發了程式碼後,即同步在 docker 內部,使開發更快速。

entrypoint中指定了go run main.go,所以我們也必須創建一個main.go檔,才會讓 docker 啟動時有檔案執行

// main.go
package main

import (
	"database/sql"
	"fmt"
	"log"
	"net/http"

	_ "github.com/lib/pq"
)

const (
  // 指定要連接的DB位置
	HOST     = "db"
	DATABASE = "postgres"
	USER     = "user"
	PASSWORD = "mysecretpassword"
)

func main() {
  // 連接DB
	db, err := sql.Open(
		"postgres",
		fmt.Sprintf("host=%s user=%s password=%s dbname=%s sslmode=disable", HOST, USER, PASSWORD, DATABASE),
	)
	if err != nil {
		panic(err)
	}
  // 檢查連接是否成功
	if err = db.Ping(); err != nil {
		panic(err)
	}
	fmt.Println("Successfully created connection to database")

  // 啟動一個簡單的http server
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "Hello World!!")
	})
	log.Fatal(http.ListenAndServe(":5000", nil))
}

指定要連接的DB位置這幾行中,HOST為 docker 容器的名稱,這邊要注意一下並不是使用什麼localhost來連接,我第一次用 Docker-Compose 時這邊卡了很久 XD,而其他的欄位就是docker-compose.yamldb裡設置的environment

啟動 Docker-Compose

將 docker 內部需要 build 的容器都 build

$ docker-compose up

build 完畢後啟動

$ docker-compose up

當你看到Successfully created connection to database字串時就代表成功啦~

有了好環境後就可以開始開發囉,接下來下篇要介紹如何透過各式各樣的 Docs tool 來幫助我們開發更順暢!


謝謝你的閱讀,也歡迎分享討論指正~

comments powered by Disqus