返回文章列表

Docker 架設 Gogs Git 服務最佳實踐

本文介紹如何在 Docker 環境中架設 Gogs Git 服務,涵蓋安裝、組態、備份、遷移以及多環境佈署等導向。同時,也探討了 Git 流程最佳實踐,包括壓縮提交、推播變更、建立 Pull Request 等,並提供專案結構、程式碼組織、依賴管理及自動化測試等建議,以提升佈署效率和程式碼品質。

Web 開發 DevOps

在 Docker 中佈署 Gogs 提供了便捷的自託管 Git 解決方案,結合版本控制與持續整合能有效提升開發效率。本文除了 Gogs 的安裝、組態及備份流程外,也涵蓋了 Git 的日常操作,如分支管理、壓縮提交及 Pull Request 建立等。此外,文章也探討了 Go 語言專案的結構規劃、依賴管理的最佳實踐以及自動化測試的重要性,以確保程式碼品質並提升佈署效率。從 Docker 容器的建置、Go 語言套件的管理到 CI/CD 流程的整合,本文提供了一套完整的技術,協助開發者建構更穩健且高效的開發流程。

在 Docker 中架設 Gogs 自託管 Git 服務

在軟體開發過程中,版本控制系統扮演著至關重要的角色。Gogs 是一個優秀的自託管 Git 服務解決方案,提供了一個簡潔高效的方式來管理程式碼倉函式庫。本文將介紹如何在 Docker 中安裝和組態 Gogs,以及如何進行備份和遷移。

為何選擇 Gogs?

目前,GitHub 和 Bitbucket 是最流行的 Git 服務提供商。Bitbucket 提供了免費的私有倉函式庫和許可權管理功能,適合小型團隊使用。然而,自託管 Git 倉函式庫可以避免諸如速率限制等問題,同時也能夠更好地控制程式碼的安全性。如果您對將程式碼託管在雲端有所顧慮,自託管也是一個不錯的選擇。未來,若需要遷移至 GitLab、GitHub 或 Bitbucket,也可以輕鬆實作。

安裝和執行 Gogs

Gogs 是使用 Go 語言開發的,提供了一系列二進位制檔案,支援多種常見的作業系統和架構,包括 Windows。然而,為了方便管理和執行,我們將使用 Docker 來佈署 Gogs。

快速啟動 Gogs 例項

#!/bin/bash
NAME="gogs"
APP_DIR=$(dirname $(readlink -f $0))
mkdir -p ${APP_DIR}/data/$NAME
docker stop $NAME
docker rm $NAME
docker run -d --net=party --restart=always --name=$NAME -h $NAME -p 10022:22 -p 3000:3000 -v ${APP_DIR}/data/$NAME:/data gogs/gogs

內容解密:

  1. 定義容器名稱和應用目錄:首先,指令碼定義了容器的名稱(NAME="gogs")和應用程式目錄(APP_DIR)。
  2. 建立資料目錄:使用 mkdir 命令建立資料目錄,以持久化儲存 Gogs 的資料。
  3. 停止和移除現有容器:如果容器已經存在,則先停止並移除它,以確保重新啟動的容器是乾淨的。
  4. 執行 Gogs 容器:使用 docker run 命令啟動 Gogs 容器,並對映必要的埠(10022 for SSH, 3000 for HTTP)。同時,將主機的資料目錄掛載到容器內的 /data 目錄,以實作資料持久化。

組態 Gogs

首次存取 http://yourserver:3000/ 時,Gogs 將引導您完成安裝過程。您可以選擇連線至 MySQL 資料函式庫或使用 SQLite3 作為後端儲存。

建立 Gogs 資料函式庫

如果您使用了 MySQL 資料函式庫,需要手動建立一個名為 gogs 的資料函式庫:

docker exec mysql mysqladmin create gogs

內容解密:

  • 使用 docker exec 命令:此命令允許您在正在執行的 Docker 容器內執行命令。
  • 建立 gogs 資料函式庫:使用 mysqladmin 命令建立一個新的資料函式庫,供 Gogs 使用。

登入和建立倉函式庫

安裝完成後,第一個註冊的使用者將自動成為管理員。您可以透過網頁介面建立新的倉函式庫,並按照指示初始化本地倉函式庫和推播程式碼。

建立新倉函式庫

mkdir the12factors
cd the12factors
touch README.md
git init
git add README.md
git commit -m "first commit"
git remote add origin http://peer.lan:3000/titpetric/the12factors.git
git push -u origin master

內容解密:

  1. 建立本地倉函式庫:使用 mkdircd 命令建立並進入新目錄。
  2. 初始化 Git 倉函式庫:使用 git init 初始化 Git 倉函式庫。
  3. 新增檔案並提交:建立 README.md 檔案,使用 git addgit commit 提交變更。
  4. 關聯遠端倉函式庫:使用 git remote add 命令將本地倉函式庫與 Gogs 上的遠端倉函式庫關聯。
  5. 推播程式碼:使用 git push 將本地變更推播至遠端倉函式庫。

備份 Gogs

若使用 SQLite 資料函式庫,備份 Gogs 相對簡單。只需停止容器,封裝資料目錄,然後重新啟動容器即可。

快速備份 Gogs

#!/bin/bash
NAME="gogs"
docker stop $NAME
cd data && tar -zcvf gogs-backup-$(date +"%Y%m%d").tgz gogs/ && cd ..
docker start $NAME

內容解密:

  1. 停止 Gogs 容器:確保資料一致性,需要先停止容器。
  2. 封裝資料目錄:使用 tar 命令封裝 data/gogs 目錄,生成當日日期的備份檔案。
  3. 重新啟動容器:備份完成後,重新啟動 Gogs 容器。

多環境佈署

使用 Git 進行版本控制時,可以透過分支管理來實作多環境佈署,如開發、預釋出和生產環境。理想的工作流程包括維護一個主分支(master),並在其他分支上進行新功能開發,最終透過 Pull Request 合併回主分支。

使用分支進行多環境佈署

# git checkout -b new-feature
# git branch

內容解密:

  1. 建立新分支:使用 git checkout -b 命令建立並切換到新分支。
  2. 檢視當前分支:使用 git branch 命令檢視當前所在分支。

綜上所述,Gogs 提供了一個靈活且易於管理的自託管 Git 服務解決方案。透過 Docker 佈署,可以簡化安裝和組態流程。同時,透過合理的備份和分支管理策略,可以確保程式碼的安全性和多環境佈署的靈活性。

專案管理與 Git 流程最佳實踐

在軟體開發過程中,良好的程式碼管理和版本控制是確保專案順利進行的關鍵。本文將探討如何使用 Git 進行有效的程式碼管理和協作,包括壓縮提交、推播變更以及建立 Pull Request 等流程。

壓縮提交(Squashing Commits)

當開發一個新功能時,通常會進行多次提交以完成相關變更。然而,在將這些變更推播到遠端儲存函式庫之前,將多個提交壓縮成一個單一提交是一個良好的實踐。這樣可以保持提交歷史的簡潔和易於理解。

如何壓縮提交

  1. 使用 git rebase -i HEAD~n 命令,其中 n 是您要壓縮的提交數量。
  2. 在互動式 rebase 編輯器中,將除了第一個提交外的其他提交的 pick 改為 squashs
  3. 編輯提交訊息以反映壓縮後的變更。
  4. 完成 rebase 後,您的提交歷史將只包含一個包含所有變更的提交。

範例:

git rebase -i HEAD~2

編輯器內容:

pick 255ac52 新增標題到 README
squash 3e9f63e 新增內容

修改後的提交訊息:

新增標題和內容到 README

推播變更

在壓縮提交後,您可以將變更推播到遠端儲存函式庫。如果之前已經推播過相關提交,您需要使用強制推播:

git push origin my-feature --force

請注意,強制推播可能會破壞其他人的工作副本,因此應謹慎使用。

建立 Pull Request

推播變更後,您可以建立一個 Pull Request(PR)以請求將您的變更合併到主分支。PR 是進行程式碼審查和自動化測試的良好機會。

簡化的 Git Fork/Branch 流程

  1. 建立 fork
  2. 複製儲存函式庫
  3. 建立分支
  4. 提交、壓縮和推播變更
  5. 提交 Pull Request

專案結構與程式碼組織

在使用 Docker 和 Go 語言進行開發時,合理的專案結構非常重要。以下是一個建議的專案結構:

$GOPATH(/go)/src/app
|__ main.go
|__ subpackage/
| |__ subpackage.go
| \__ ...
|__ ... (其他檔案或子套件)
\__ vendor/
|__ github.com/namsral/flag
|__ github.com/gorilla/mux
\__ ...

使用子套件

您可以透過 import "app/subpackage" 的方式匯入子套件。如果需要,您也可以使用完全合格的網域名稱來匯入套件。

範例:

package main

import "app/apiservice"

func main() {
    apiservice.HelloWorld()
}

相對匯入與子套件外部使用

避免相對匯入

相對匯入可能會導致 vendoring 出現問題,因此建議避免使用。

子套件的外部使用

如果您的子套件需要被外部專案使用,請確保它們是自包含的,或者使用完全合格的匯入路徑。

範例:

// 不建議
package subpackage1

import "app/subpackage2"

// 建議
package subpackage1

import "example.github.com/username/your-app/subpackage2"

解耦子套件

為了避免子套件之間的緊密耦合,可以使用依賴注入等方式來實作鬆散耦合。

提升佈署效率與自動化測試

在進行佈署時,從一開始就實施自動化是非常重要的。使用持續整合(CI)系統是必不可少的。許多開發者使用像 Jenkins 或 Travis 這樣的工具,或者選擇 Buildkite 或 Codeship 這樣的託管服務。

自動化測試的重要性

在開發初期編寫測試相對容易,但當應用程式已經上線後,再新增測試就會變得困難得多。在 CI 工作流程中加入測試,可以確保不會發布任何測試失敗的專案。

對於 Go 應用程式,最簡單的測試方法是執行 go test,但這只是測試的一部分。如果正在構建 Docker 映像,也應該為其設定測試程式。

確保建置過程的一步到位

應該確保可以一步完成建置。通常在專案根目錄下包含一個 build.sh 檔案就足夠了,然後使用任何 CI 套件來執行它。根據專案大小,這可能需要呼叫像 ant 或 make 這樣的工具。

佈署前的測試條件

測試程式必須是佈署應用程式的先決條件。如果測試未透過,應該通知觸發佈署的人。雖然不一定要馬上修復,但在此之前,不應允許佈署。

依賴管理:明確宣告與隔離

Go 語言內建了用於安裝套件的 go get 命令。雖然可以使用它來安裝應用程式所需的套件,但無法控制安裝的套件版本。因此,為了實作可重複的建置過程,建議使用 vendoring。

Vendoring 的實踐

對於來自 PHP、Python 或 Node 的開發者來說,他們有 composer、pip 和 npm 等套件管理工具。在 Go 中,有多種套件管理工具可供選擇,例如 gvt 和 glide。

使用 gvt 取得依賴

使用 gvt fetch 命令可以取得依賴套件,並將其寫入 vendor/ 目錄下。應該將該目錄提交到版本控制系統,以備未來建置使用。

gvt fetch github.com/namsral/flag

管理依賴版本

可以使用 gvt list 命令列出目前的依賴套件。如果需要更新依賴,可以執行 gvt update,然後提交 vendor/ 目錄下的變更。

$ gvt list
github.com/namsral/flag https://github.com/namsral/flag master 881a43080604bcf99ab11\
18a814d1cb2c268fc36

設定 .gitignore

如果不想將套件提交到原始碼倉函式庫,可以在 .gitignore 檔案中新增規則,只提交 manifest 檔案。

1 vendor/**
2 !vendor/manifest

這樣,在進行 clean build 時,可以透過 gvt restore 命令擷取 manifest 檔案中宣告的所有依賴。

使用 Vendoring 的注意事項

Vendoring 可以提供對套件版本的精細控制,但也有一些需要注意的事項。例如,當程式碼或其子套件依賴不同版本的相同套件時,需要修復程式碼以使其相容。

相對匯入

在應用程式中,可能會使用相對匯入。有些套件管理工具,如 gopkg.in,支援透過 URL 指定標籤或分支來匯入依賴。

程式碼管理最佳實踐

在進行程式碼管理時,保持團隊的參與和責任感非常重要。當出現問題時,應該指定負責修復的人,而不是追究責任。

#### 內容解密:

上述段落主要闡述了在軟體開發過程中,如何透過自動化測試、持續整合(CI)和依賴管理來提升佈署效率和程式碼品質。首先,強調了自動化測試和 CI 的重要性,並介紹瞭如何使用 go test 和其他工具來進行測試。其次,討論了依賴管理的方法,特別是使用 vendoring 來控制套件版本。最後,提到了使用 vendoring 時需要注意的事項,以及如何保持團隊的參與和責任感。這些最佳實踐有助於確保軟體開發的品質和效率。

依賴管理:明確宣告與隔離依賴

相對路徑匯入的問題

在 Go 語言中,使用相對路徑進行匯入是一種常見的模式,例如:

import "./subpackage"

然而,這種方式與 vendoring 機制不相容。如果你的套件使用了 vendored 匯入,應用程式將無法正確編譯。建議使用絕對路徑匯入,例如:

import "app/subpackage"

這種方式會在 $GOPATH/src/app/subpackage 資料夾中尋找檔案,這正是你的檔案存放的位置。相對路徑匯入目前與 vendoring 機制存在相容性問題。

內容解密:

  1. 相對路徑匯入:使用 ./ 開頭的匯入路徑,例如 ./subpackage
  2. 絕對路徑匯入:使用完整的套件路徑,例如 app/subpackage
  3. Vendoring 機制:一種管理依賴套件的方式,將依賴的套件複製到專案的 vendor 目錄下。

系統依賴

在建立 Docker 映像檔時,使用 Dockerfile 宣告依賴。例如,建立一個包含 bash 的 Docker 映像檔:

FROM alpine
RUN apk add --no-cache bash

這宣告了應用程式的依賴。透過建立 Docker 映像檔,映像檔本身與其他容器隔離。

內容解密:

  1. FROM alpine:使用 Alpine Linux 作為基礎映像檔。
  2. RUN apk add --no-cache bash:安裝 bash 套件。
  3. 隔離性:Docker 映像檔之間的隔離性,確保不同容器之間的獨立性。

建立 Docker 映像檔

你可以組合多個 Docker 映像檔。例如,使用官方的 Go 語言映像檔 golang:1.8-alpine

FROM golang:1.8-alpine
RUN go get -u github.com/FiloSottile/gvt

或者,建立一個包含多個工具的「大」Go 語言映像檔:

FROM golang:1.8-alpine
MAINTAINER Tit Petric <[email protected]>

## install needed packages
RUN apk --no-cache add gcc musl-dev git

## add external get packages
RUN go get -u github.com/FiloSottile/gvt && \
    go get -u github.com/Masterminds/glide && \
    go get -u github.com/kisielk/errcheck && \
    go get -u github.com/golang/lint/golint && \
    go get -u github.com/goreleaser/goreleaser

內容解密:

  1. FROM golang:1.8-alpine:使用官方的 Go 語言映像檔作為基礎。
  2. RUN go get:安裝指定的 Go 語言套件。
  3. 多階段構建:可以根據需求選擇不同的基礎映像檔和安裝不同的套件。

單一職責原則

雖然建立一個包含多個工具的大映像檔看似方便,但這違反了單一職責原則。建議為每個工具建立獨立的映像檔,以確保可維護性和可擴充套件性。

內容解密:

  1. 單一職責原則:每個容器或映像檔應該只負責一個任務或服務。
  2. 可維護性:獨立的映像檔更容易維護和更新。
  3. 可擴充套件性:獨立的映像檔更容易擴充套件和重複使用。

不同階段的依賴

在不同的構建、發布和執行階段,依賴可能有所不同。例如,在構建階段可能需要不同版本的 Go 語言,而在發布和執行階段則不需要。

內容解密:

  1. 構建階段:需要特定的工具和依賴,例如不同版本的 Go 語言。
  2. 發布和執行階段:只需要編譯好的應用程式二進位制檔案,不需要構建工具。
  3. 依賴管理:根據不同的階段選擇合適的依賴和工具。

使用 Docker Hub 中的映像檔

Docker Hub 提供了許多官方和社群維護的映像檔,可以根據需求選擇合適的映像檔。

內容解密:

  1. Docker Hub:一個存放和分享 Docker 映像檔的平台。
  2. 官方映像檔:由軟體官方維護的映像檔,例如 Go 語言官方映像檔。
  3. 社群映像檔:由社群使用者維護的映像檔,可能包含特定的工具或設定。