2022-03-07 09:07阅读: 386评论: 0推荐: 0

制作gogs docker镜像

文章背景:由于网络原因访问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的理解又有了更深一点的了解,希望对大家有所帮助。

本文作者:三点一圆

本文链接:https://www.cnblogs.com/sandianyiyuan/p/15972393.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   三点一圆  阅读(386)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起