1. 程式人生 > 其它 >製作gogs docker映象

製作gogs docker映象

由於網路原因訪問Github經常不穩定,準備在公司部署一套基於Docker的Gogs服務,用於定時同步Github上的專案。 公司網路環境不能直接使用gogs專案中原本的構建流程,同時為了節省構建過程中下載依賴包花費的時間,考慮將其Dockerfile中編譯環境和執行的構建步驟拆出來,製作成兩個映象放在私有倉庫中,然後再基於製作好的映象構建gogs映象。本文詳細記錄了這一過程。

文章背景:由於網路原因訪問Github經常不穩定,準備在公司部署一套基於Docker的Gogs服務,用於定時同步Github上的專案。
公司網路環境不能直接使用gogs專案中原本的構建流程,同時為了節省構建過程中下載依賴包花費的時間,考慮將其Dockerfile中編譯環境和執行的構建步驟拆出來,製作成兩個映象放在私有倉庫中,然後再基於製作好的映象構建gogs映象。本文詳細記錄了這一過程。

Gogs 的目標是打造一個最簡單、最快速和最輕鬆的方式搭建自助 Git 服務。使用 Go 語言開發使得 Gogs
能夠通過獨立的二進位制分發,並且支援 Go 語言支援的 所有平臺,包括 Linux、Mac OS X、Windows 以及 ARM 平臺。
----

gogs官方網站:https://gogs.io/docs/

官方文件說使用二進位制安裝非常方便,只需要下載編譯好的二進位制檔案,啟動服務就行。
按照循序漸進的原則,先在windows中用二進位制安裝,預覽看看gogs到底有一些什麼功能,安裝是不是真的簡單。

一、在window下安裝gogs

  1. 下載壓縮包
    在網找到Windows系統對應的安裝包下載地址
  2. 將壓縮包解壓,得到以下檔案內容:

    3.開啟按win+R輸入cmd開啟命令列,cd進入gogs目錄。
    例如我的gogs目錄路徑是D:\Program Files\gogs,首先執行D:回車進入D盤,再輸入cd D:\Program Files\gogs
    ,進入gogs目錄

4.啟動gogs服務,執行指令gogs web:

看到以上提示說明gogs啟動成功,開啟瀏覽器訪問 locahost:3000 就能看到gogs的頁面了。

根據頁面提示進行後續的安裝步驟,主要是一些配置內容,配置好後點擊立即安裝
如果配置了管理員賬戶,安裝完成後自動登入到管理員賬戶中,否則跳轉到登入頁面,第一個註冊使用者為管理員賬戶。
為了安裝的方便,資料庫可以直接使用SQLite3,這樣就不需要另外安裝資料庫應用。
windows上的安裝步驟就到這裡了,主要是為了看一下gogs是個什麼應用,大概有一些什麼功能。

二、在windos下從原始碼安裝

1. 首先準備環境

本機為win10,需要安裝go語言。
a. 安裝GO語言參考文件:

http://c.biancheng.net/view/3992.html,這裡就不詳細介紹了。
Go語言下載地址:官方 https://golang.google.cn/dl/中國Golang社群 https://studygolang.com/dl
b. 安裝git:下載地址:https://git-scm.com/

2. 克隆gogs專案原始碼

在bash中執行指令:git clone --depth 1 https://github.com/gogs/gogs.git gogs

3. 編譯主程式

執行go build -o gogs 編譯主程式
這個步驟會下載所有依賴。正常情況可以看到正在下載依賴包的輸出內容:

也可能會出現指令執行後反應的現象,導致這個問題的原因有兩個:
a. 下載go模組速度慢;
b. gcc沒正確安裝。

  1. 下載速度慢,設定go代理解決:
    執行go env可以檢視go配置,將其修改為七牛雲 https://goproxy.cn/提供的代理:
    go env -w GO111MODULE=on
    go env -w GOPROXY=https://goproxy.cn,direct
    
  1. gcc沒正確安裝。
    gcc未安裝報錯:

    	cgo: C compiler "gcc" not found: exec: "gcc": executable file not found in %PATH%
    

    gcc 版本不正確報錯:

    cc1.exe: sorry, unimplemented: 64-bit mode not compiled in
    
     ![](https://img2022.cnblogs.com/blog/996442/202203/996442-20220306160014132-1879010011.png)
    

    安裝GCC參考文件:https://blog.csdn.net/xia_2017/article/details/105545789
    下載地址:https://sourceforge.net/projects/mingw-w64/files/mingw-w64/mingw-w64-release/
    下載64位x86_64-posix-seh壓縮包,解壓後將bin目錄配置到環境變數的path中,執行gcc -v可以看到gcc資訊:

以上配置之後再嘗試重新編譯。
使用go env指令可以看到GOMODCACHE=C:\Users\Administrator\go\pkg\mod變數,build時下載的模組是儲存該目錄下的。
編譯完成之後在gogs目錄下會生成gogs.exe,在bash中執行指令gogs web可啟動服務,跟之前下載的二進位制檔案效果一樣,訪問 localhost:3000 即可看到web頁面。

三、製作docker映象

在windows下已經知道了如何編譯,接下來換到docker中把這個流程再跑一遍,因為最終的目標是根據原始碼編譯釋出一個自己的映象,用於在Docker中執行。
使用Docker有很多好處,能避免各種環境問題。

1. 安裝Docker:

win10系統,在官網下載應用包安裝,跟普通應用安裝差不多,詳細文件網上有很多。
裝好Docker後,執行docker -v可以看到版本資訊,則說明安裝成功了。

將Gogs目錄中的Dockerfile檔案開啟檢視其中內容,根據Dockerfile的步驟在容器中手動操作一次。

FROM golang:alpine3.14 AS binarybuilder        # 基於golang:alpine3.14映象進行後續步驟
RUN apk --no-cache --no-progress add --virtual \    # 使用apk包管理器安裝一些編譯需要用到的工具
  build-deps \
  build-base \
  git \
  linux-pam-dev

WORKDIR /gogs.io/gogs    # 進入目錄
COPY . .    # 將宿主機中當前目錄中的內容拷貝到容器中
RUN make build TAGS="cert pam"    # 開始構建。

FROM alpine:3.14
RUN if [ `uname -m` == "aarch64" ] ; then \
      export arch="arm64" ; \
  elif [ `uname -m` == "armv7l" ] ; then \
      export arch="armhf"; \
  else \
      export arch="amd64" ; \
  fi \
  && wget https://github.com/tianon/gosu/releases/download/1.11/gosu-$arch -O /usr/sbin/gosu \
  && chmod +x /usr/sbin/gosu \
  && echo http://dl-2.alpinelinux.org/alpine/edge/community/ >> /etc/apk/repositories \
  && apk --no-cache --no-progress add \
  bash \
  ca-certificates \
  curl \
  git \
  linux-pam \
  openssh \
  s6 \
  shadow \
  socat \
  tzdata \
  rsync

ENV GOGS_CUSTOM /data/gogs

# Configure LibC Name Service
COPY docker/nsswitch.conf /etc/nsswitch.conf

WORKDIR /app/gogs
COPY docker ./docker
COPY --from=binarybuilder /gogs.io/gogs/gogs .

RUN ./docker/finalize.sh

# Configure Docker Container
VOLUME ["/data", "/backup"]
EXPOSE 22 3000
HEALTHCHECK CMD (curl -o /dev/null -sS http://localhost:3000/healthcheck) || exit 1
ENTRYPOINT ["/app/gogs/docker/start.sh"]
CMD ["/bin/s6-svscan", "/app/gogs/docker/s6/"]

2. 準備編譯環境golang:alpine3.14

其中1~9行執行的過程其實就是在準備編譯環境,然後對原始碼進行編譯。
跟在本機電腦中做的是一回事。

2.1 執行一個基礎映象

執行Dockerfile中的第一行FROM golang:alpine3.14 AS binarybuilder,該行內容表示基於golang:alpine3.14這個映象執行後面的指令,手動執行同樣需要使用這個基礎映象執行一個容器,之後才能基於這個容器進行後面的操作,手動執行指令:

docker run -it --name golang golang:alpine3.14

說明:docker映象啟動後,如果容器中沒有任何的程序則會自動退出,後續還要執行指令安裝基礎應用軟體,因此不能讓容器退出,加上-it引數可以在容器啟動後自動進入容器中從而阻止容器退出,進入容器後顯示的當前所在目錄為/go
也可以使用-itd引數,後臺啟動容器,這時候要進入一個容器需要使用指令docker attach ContainerID

檢視ContainerID的指令: docker ps檢視正在執行的容器、docker ps -a檢視所有容器。

2.2 在基礎映象的容器中安裝軟體

2.2.1 配置apk源

設定pak軟體源,執行指令快速將配置檔案/etc/apk/repositories中的https://dl-cdn.alpinelinux.org替換為http://mirrors.ustc.edu.cn/alpine

sed -i 's#https://dl-cdn.alpinelinux.org#http://mirrors.ustc.edu.cn/alpine#g' /etc/apk/repositories

也可以手動將配置檔案中的源設定為其他可用的源,在https://mirrors.alpinelinux.org/中可以找到其他可用的源。

2.2.2 安裝基礎應用

執行Dockerfile中的第2~6行,這一行其實是一個指令。
在Dockerfile中使用\來換行,寫到一行就是apk --no-cache --no-progress add --virtual build-deps build-base git linux-pam-dev

安裝完成後使用apk info可以看到已安裝的應用列表,指令應該是能正常使用的,如果不能正常使用,一定要重新安裝,否則後基於有問題的映象進行後續的操作會報錯,而且很難排查。

2.2.4 打包基礎映象

容器中軟體安裝完成後基礎環境就準備完成,可以將其打包成映象,以後需要編譯gogs程式直接使用帶有基礎環境的映象。
需要用的的指令

docker ps # 檢視容器的ID
docker commit -m "" CONTAINERID TAG # 將容器打包成映象

指令都是在宿主機中進行的。

到此,gogs的編譯環境映象就製作完成了

2.2.5 apk安裝軟體失敗問題解決

apk安裝軟體可能會遇到錯誤(沒遇到錯誤可直接忽略)

 fetch https://dl-cdn.alpinelinux.org/alpine/v3.14/main/x86_64/APKINDEX.tar.gz
WARNING: Ignoring https://dl-cdn.alpinelinux.org/alpine/v3.14/main: temporary error (try again later)
fetch https://dl-cdn.alpinelinux.org/alpine/v3.14/community/x86_64/APKINDEX.tar.gz
WARNING: Ignoring https://dl-cdn.alpinelinux.org/alpine/v3.14/community: temporary error (try again later)
ERROR: unable to select packages:
  build-base (no such package):
    required by: build-deps-20220305.081134[build-base]
  git (no such package):
    required by: build-deps-20220305.081134[git]
  linux-pam-dev (no such package):
    required by: build-deps-20220305.081134[linux-pam-dev]

可以看到執行有報錯,並沒有成功,是因為apk在倉庫中沒有找到對應的軟體包,需要修改apk的源才能成功安裝。
apk的源配置在檔案/etc/apk/repositories中,當前配置為:

https://dl-cdn.alpinelinux.org/alpine/v3.14/main
https://dl-cdn.alpinelinux.org/alpine/v3.14/community

在這裡https://mirrors.alpinelinux.org/找到其他可用的源,將配置檔案修改後,重新執行指令安裝。
執行指令sed -i 's#https://dl-cdn.alpinelinux.org#http://mirrors.ustc.edu.cn/alpine#g' /etc/apk/repositories快速將https://dl-cdn.alpinelinux.org替換為http://mirrors.ustc.edu.cn/alpine,也可手動修改。
https不行可以換http試一下。
到此,gogs的編譯環境映象就製作完成,以後程式碼有修改就可以直接使用製作好的映象,在裡面使用make build指令直接編譯程式而不用先下載所需的軟體了,這時候就能體會到docker的方便之處了。

3. 編譯 gogs 測試基礎映象可用性

剛剛製作好的映象如果沒問題的話,是具備編譯gogs的環境的,啟動這個映象,嘗試編譯一下gogs的原始碼,看能否編譯成功。
Dockerfile的第8、9、10行就是編譯指令

WORKDIR /gogs.io/gogs    # 進入目錄
COPY . .    # 將宿主機中當前目錄中的內容拷貝到容器中
RUN make build TAGS="cert pam"    # 開始構建

Dockerfie中的WORKDIR相於在容器中執行cd指令切換目錄,如果目錄不存在,會自動建立。
COPY 是將宿主機中的檔案拷貝到容器中,Dockerfile檔案構建容器時,上下文目錄就Dockerfile檔案所在的目錄,因此,COPY . .這行就是將宿主機中當前目錄的所有內容拷貝到容器中。
在原Dockerfile中是將兩個階段的構建寫在同一個檔案中的,前一階段容器中的檔案可以通過COPY --from指令拷貝到後面階段的容器中,--from後面跟上前一階段容器的別名,也就是前一階段FROM指令行AS後的名字。

3.1 執行一個帶有編譯環境的容器

手動執行時,我們直接從宿主機中對映檔案目錄替代拷貝檔案,啟動容器時使用-v引數將宿主機目錄對映到容器的WORKDIR目錄,所以使用剛才製作的映象啟動一個容器這樣執行:

docker run -it --name test-build-gogs -it -v "E:\git\gogs:/gogs.io/gogs" golang:buildEnvironment-test

啟動後進入容器,可以看到宿主機目錄中的檔案,在宿主機中修改的檔案在容器中也能看到變化:

目錄對映成功。

3.2 設定go模組代理

ps:沒有在製作基礎環境的時候將代理配置進去是因為在不同的環境中使用映象所需要的代理可能不同,因此在使用映象時自行配置代理,網路正常可以省略這個步驟。
執行指令

go env -w GO111MODULE=on
go env -w GOPROXY=https://goproxy.cn,direct

3.3 編譯

執行Dockerfie的第10行指令

make build TAGS="cert pam"

如果build沒反應,設定go代理後再嘗試。

最後編譯成功,會輸出名為gogs的檔案在宿主幾中也能看到:

到這裡 gogs的編譯環境映象測試通過,可以將基礎映象往倉庫push,釋出出來供大家使用了。

4. 製作gogs的執行環境

為什麼要製作這麼多的映象,因為軟體的編譯環境是很複雜的,軟體編譯好之後,編譯環境在軟體執行過程中並沒有用,因此單獨製作一個軟體執行所需要的最小環境就行,這樣在映象分發的時候可以提高效率,避免資源的浪費。
Dockerfile第12~14行:

FROM alpine:3.14
RUN if [ `uname -m` == "aarch64" ] ; then \
      export arch="arm64" ; \
  elif [ `uname -m` == "armv7l" ] ; then \
      export arch="armhf"; \
  else \
      export arch="amd64" ; \
  fi \
  && wget https://github.com/tianon/gosu/releases/download/1.11/gosu-$arch -O /usr/sbin/gosu \
  && chmod +x /usr/sbin/gosu \
  && echo http://dl-2.alpinelinux.org/alpine/edge/community/ >> /etc/apk/repositories \
  && apk --no-cache --no-progress add \
  bash \
  ca-certificates \
  curl \
  git \
  linux-pam \
  openssh \
  s6 \
  shadow \
  socat \
  tzdata \
  rsync

執行一個映象:

docker run -it --name gogsRyantime-test alpine:3.14

13~19行是判斷系統位數,需要根據系統位數下載一個依賴檔案gosu-amd64,

如果網路不好的情況下可能從github下載失敗,可以在網上找到其它可下載的地址,將下載地址替換掉
或者使用-v引數將包含有這個檔案的路徑掛載到容器中,再將檔案拷貝到/usr/sbin/路徑下。
並修改檔案的許可權:chmod +x /usr/sbin/gosu,一定要記得修改許可權,否則後面容器啟不了

安裝軟體:

軟體安裝完成後,將其打包成映象:

docker commit -m "打包gogs執行環境"c80a108 alpine_3.14:gogsRuntime-test

5. 製作gogs docker映象

執行環境映象製作好之後,就可以使用這個映象來製作含有gogs的映象了,後面的步驟就不再使用進入容器中操作了,直接使用Dockerfie操作後續的步驟
將原來的Dockerfile檔案備份,另外建立一個Dockerfile檔案。
其中的內容為:

FROM alpine_3.14:gogsRuntime-test
ENV GOGS_CUSTOM /data/gogs
# Configure LibC Name Service
COPY docker/nsswitch.conf /etc/nsswitch.conf
WORKDIR /app/gogs
COPY docker ./docker
COPY gogs gogs 
#COPY --from=binarybuilder /gogs.io/gogs/gogs .
RUN ./docker/finalize.sh
# Configure Docker Container
VOLUME ["/data", "/backup"]
EXPOSE 22 3000
HEALTHCHECK CMD (curl -o /dev/null -sS http://localhost:3000/healthcheck) || exit 1
ENTRYPOINT ["/app/gogs/docker/start.sh"]
CMD ["/bin/s6-svscan", "/app/gogs/docker/s6/"]

執行docker build -t mygogs-test .,生成帶有gogs程式的映象:

執行過程中可能看到報錯提示failed to compute cache key: "xxx" not found: not found
這是因為原始Dockerfile兩個階段合併在一起,出於某些原因在.dockerignore檔案中,將gogs忽略掉了。
將gogs重新命名為gogsAPP,並在Dockerfile中使用新的檔名進行拷貝就可以了
另外特別說明:在windows系統下,在容器中呼叫.sh可能會失敗
提示提示錯誤executor failed running [xxx.sh]:exit code: 127

這是由於啟動指令碼中的換行符導致的。
windows系統中的換行符在Dockerfile構建映象被呼叫時不能正確解析。請用notepad++開啟docker build時使用到的.sh檔案,檢查換行符號,是否為\n,如果不是修改換行符再試。
這個問題排查了半天,在window和虛擬機器中不斷刪精簡指令碼,不斷執行docker build嘗試,最後發現在windos環境中構建時,不呼叫.sh指令碼就能構建呼叫就不行,那問題定位到sh指令碼了,再逐行刪除精簡,不段換sh指令碼中的指令,即將放棄的時候想到會不會是換行符的問題?修改換行符終於解決了。
一杯茶一支菸,一個問題查半天...

將換行符全部替換掉,再構建就成功了:

6.執行帶有gogs容器的映象

docker run -itd --name mggogs-test -v "/data:/data" -p 3000:3000 mygogs-test

訪問localhost:3000如果順利,你將再次看到gogs的web頁面

到這裡,我們一共做了三個映象,一個編譯gogs程式的映象,一個gogs執行環境的映象,在執行環境的基礎上又增加了包含gogs程式的映象。
最終的產物是可直接在docker中一鍵啟動執行的gogs映象。

這裡遇到一個坑:
前面準備執行環境映象時chmod +x /usr/sbin/gosu指令沒執行,導致製作出來的容器啟動容器時報錯:standard_init_linux.go:228: exec user process caused: no such file or directory

網上查說什麼系統架構導致的檔案找不到,加上以上過程都是在windods上做的,問題就更復雜了。
正準備放棄的時候回頭看之前的操作過程發現漏了一步,重新把許可權修改後繼續做後面的終於成功了。
寫本文件時,重新把這個過程走了一遍,對docker的理解又有了更深一點的瞭解,希望對大家有所幫助。