在 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
內容解密:
- 定義容器名稱和應用目錄:首先,指令碼定義了容器的名稱(
NAME="gogs")和應用程式目錄(APP_DIR)。 - 建立資料目錄:使用
mkdir命令建立資料目錄,以持久化儲存 Gogs 的資料。 - 停止和移除現有容器:如果容器已經存在,則先停止並移除它,以確保重新啟動的容器是乾淨的。
- 執行 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
內容解密:
- 建立本地倉函式庫:使用
mkdir和cd命令建立並進入新目錄。 - 初始化 Git 倉函式庫:使用
git init初始化 Git 倉函式庫。 - 新增檔案並提交:建立
README.md檔案,使用git add和git commit提交變更。 - 關聯遠端倉函式庫:使用
git remote add命令將本地倉函式庫與 Gogs 上的遠端倉函式庫關聯。 - 推播程式碼:使用
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
內容解密:
- 停止 Gogs 容器:確保資料一致性,需要先停止容器。
- 封裝資料目錄:使用
tar命令封裝data/gogs目錄,生成當日日期的備份檔案。 - 重新啟動容器:備份完成後,重新啟動 Gogs 容器。
多環境佈署
使用 Git 進行版本控制時,可以透過分支管理來實作多環境佈署,如開發、預釋出和生產環境。理想的工作流程包括維護一個主分支(master),並在其他分支上進行新功能開發,最終透過 Pull Request 合併回主分支。
使用分支進行多環境佈署
# git checkout -b new-feature
# git branch
內容解密:
- 建立新分支:使用
git checkout -b命令建立並切換到新分支。 - 檢視當前分支:使用
git branch命令檢視當前所在分支。
綜上所述,Gogs 提供了一個靈活且易於管理的自託管 Git 服務解決方案。透過 Docker 佈署,可以簡化安裝和組態流程。同時,透過合理的備份和分支管理策略,可以確保程式碼的安全性和多環境佈署的靈活性。
專案管理與 Git 流程最佳實踐
在軟體開發過程中,良好的程式碼管理和版本控制是確保專案順利進行的關鍵。本文將探討如何使用 Git 進行有效的程式碼管理和協作,包括壓縮提交、推播變更以及建立 Pull Request 等流程。
壓縮提交(Squashing Commits)
當開發一個新功能時,通常會進行多次提交以完成相關變更。然而,在將這些變更推播到遠端儲存函式庫之前,將多個提交壓縮成一個單一提交是一個良好的實踐。這樣可以保持提交歷史的簡潔和易於理解。
如何壓縮提交
- 使用
git rebase -i HEAD~n命令,其中n是您要壓縮的提交數量。 - 在互動式 rebase 編輯器中,將除了第一個提交外的其他提交的
pick改為squash或s。 - 編輯提交訊息以反映壓縮後的變更。
- 完成 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 流程
- 建立 fork
- 複製儲存函式庫
- 建立分支
- 提交、壓縮和推播變更
- 提交 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 機制存在相容性問題。
內容解密:
- 相對路徑匯入:使用
./開頭的匯入路徑,例如./subpackage。 - 絕對路徑匯入:使用完整的套件路徑,例如
app/subpackage。 - Vendoring 機制:一種管理依賴套件的方式,將依賴的套件複製到專案的
vendor目錄下。
系統依賴
在建立 Docker 映像檔時,使用 Dockerfile 宣告依賴。例如,建立一個包含 bash 的 Docker 映像檔:
FROM alpine
RUN apk add --no-cache bash
這宣告了應用程式的依賴。透過建立 Docker 映像檔,映像檔本身與其他容器隔離。
內容解密:
FROM alpine:使用 Alpine Linux 作為基礎映像檔。RUN apk add --no-cache bash:安裝 bash 套件。- 隔離性: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
內容解密:
FROM golang:1.8-alpine:使用官方的 Go 語言映像檔作為基礎。RUN go get:安裝指定的 Go 語言套件。- 多階段構建:可以根據需求選擇不同的基礎映像檔和安裝不同的套件。
單一職責原則
雖然建立一個包含多個工具的大映像檔看似方便,但這違反了單一職責原則。建議為每個工具建立獨立的映像檔,以確保可維護性和可擴充套件性。
內容解密:
- 單一職責原則:每個容器或映像檔應該只負責一個任務或服務。
- 可維護性:獨立的映像檔更容易維護和更新。
- 可擴充套件性:獨立的映像檔更容易擴充套件和重複使用。
不同階段的依賴
在不同的構建、發布和執行階段,依賴可能有所不同。例如,在構建階段可能需要不同版本的 Go 語言,而在發布和執行階段則不需要。
內容解密:
- 構建階段:需要特定的工具和依賴,例如不同版本的 Go 語言。
- 發布和執行階段:只需要編譯好的應用程式二進位制檔案,不需要構建工具。
- 依賴管理:根據不同的階段選擇合適的依賴和工具。
使用 Docker Hub 中的映像檔
Docker Hub 提供了許多官方和社群維護的映像檔,可以根據需求選擇合適的映像檔。
內容解密:
- Docker Hub:一個存放和分享 Docker 映像檔的平台。
- 官方映像檔:由軟體官方維護的映像檔,例如 Go 語言官方映像檔。
- 社群映像檔:由社群使用者維護的映像檔,可能包含特定的工具或設定。