如何与 Golang、Docker 和 GitLab CI 交朋友

2025-06-07

如何与 Golang、Docker 和 GitLab CI 交朋友

让我们首先演示一下我们将用作示例的简单应用程序:

package main

import (
    "log"
    "net/http"

    "github.com/gorilla/mux"
)

var port = "8080"

func main() {
    log.Fatal(http.ListenAndServe(":"+port, router()))
}

func router() http.Handler {
    r := mux.NewRouter()
    r.Path("/greeting").Methods(http.MethodGet).HandlerFunc(greet)
    return r
}

func greet(w http.ResponseWriter, req *http.Request) {
    _, _ = w.Write([]byte("Hello, world!"))
}
Enter fullscreen mode Exit fullscreen mode

另外,我们添加一个小测试:

package main

import (
    "net/http"
    "net/http/httptest"
    "testing"
)

func TestRouter(t *testing.T) {
    w := httptest.NewRecorder()
    req := httptest.NewRequest(http.MethodGet, "/greeting", nil)
    router().ServeHTTP(w, req)

    expected := "Hello, world!"
    actual := w.Body.String()
    if expected != actual {
        t.Fatalf("Expected %s but got %s", expected, actual)
    }
}
Enter fullscreen mode Exit fullscreen mode

这很简单。我想强调的是,我们有一个外部依赖项。为了管理它(以及未来的依赖项),我们将使用dep

dep init -v -no-examples
Enter fullscreen mode Exit fullscreen mode

为了证明一切正常,我们在本地运行测试、构建并试用我们的应用程序:

$ go test ./...
ok      gitlab.com/hypnoglow/example-go-docker-gitlab   0.016s

$ go build -o app .
$ ./app

# and in another terminal:
$ curl http://localhost:8080/greeting
Hello, world!
Enter fullscreen mode Exit fullscreen mode

看起来很简单。现在我们要将我们的应用程序docker化。

问题:我们如何将依赖项传递给 docker 构建过程?

  • 选项 1:使用命令将vendor目录与源代码一起传递。COPY

  • 选项 2:使用在构建时安装依赖项RUN dep ensure

第一种选择比第二种选择有几个好处:

  • 我们(通常)已经在本地安装了供应商,何必在构建时再安装它们呢?这样可以加快docker build进程。
  • 如果存在私有依赖项,例如你的包位于另一个私有仓库中,你需要将 git 凭据传递给 docker 构建过程,以便 go 工具能够获取这些依赖项。在第一种方案中,你不会遇到这样的问题。

因此,我们创建以下 Dockerfile:

FROM golang:1.10-alpine3.7 as build

WORKDIR /go/src/app

COPY . .

RUN go build -o app

FROM alpine:3.7

COPY --from=build /go/src/app/app /usr/local/bin/app

ENTRYPOINT ["/usr/local/bin/app"]
Enter fullscreen mode Exit fullscreen mode

接下来,我们需要一个.gitlab-ci.yml文件来运行测试并在推送时构建镜像。我们该如何完成这些任务呢?

好吧,我们需要一个作业来安装依赖项,因为上面我们决定不在 Dockerfile 中安装它们。即使安装了,我们也需要安装它们才能运行测试。因此,我们创建一个作业dep来安装依赖项,并将vendor目录存储为 GitLab 工件。在其他作业中,我们将dep作业添加为依赖项,GitLab 会将之前存储的依赖项vendor直接提取到我们的项目目录中。

variables:
  PACKAGE_PATH: /go/src/gitlab.com/hypnoglow/example-go-docker-gitlab

stages:
  - dep
  - test
  - build

# A hack to make Golang-in-Gitlab happy
.anchors:
  - &inject-gopath
      mkdir -p $(dirname ${PACKAGE_PATH})
      && ln -s ${CI_PROJECT_DIR} ${PACKAGE_PATH}
      && cd ${PACKAGE_PATH}

dep:
  stage: dep
  image: golang:1.10-alpine3.7
  before_script:
    - apk add --no-cache curl git
    - curl -sSL https://github.com/golang/dep/releases/download/v0.5.0/dep-linux-amd64 -o /go/bin/dep
    - chmod +x /go/bin/dep
    - *inject-gopath
  script:
    - dep ensure -v -vendor-only
  artifacts:
    name: "vendor-$CI_PIPELINE_ID"
    paths:
      - vendor/
    expire_in: 1 hour

test:
  stage: test
  dependencies:
    - dep
  image: golang:1.10-alpine3.7
  before_script:
    - *inject-gopath
  script:
    - go test ./...

build:
  stage: build
  dependencies:
    - dep
  image: docker:17
  services:
    - docker:dind
  script:
    - docker build -t app .
Enter fullscreen mode Exit fullscreen mode

最后,我们检查管道:

管道

大功告成!接下来的步骤,比如将构建好的镜像推送到 Docker 仓库,就留给读者练习吧。🙂

完整示例可在GitLab 存储库中找到。

谢谢!这是我在dev.to上的第一篇文章,希望你喜欢。

由于英语不是我的母语,我对于任何语法和语言错误深表歉意。如果您发现任何错误,请在评论中指出! 🤓

文章来源:https://dev.to/hypnoglow/how-to-make-friends-with-golang-docker-and-gitlab-ci-4bil
PREV
DNS 揭秘💪
NEXT
为什么我不再使用 console.log() 来检查 React 状态更新 Console.table()