【问题标题】:OCI runtime create failed: container_linux.go:345OCI 运行时创建失败:container_linux.go:345
【发布时间】:2020-06-05 22:06:27
【问题描述】:

目前我们正在从 GitLab 迁移到 GitHub,我们决定将 CI/CD 流程迁移到 GitHub 操作。管道过程就像一个魅力,但当 GKE 尝试启动新推送的图像时,它会返回此错误:

'OCI runtime create failed: container_linux.go:345: starting container process caused "exec: \"/socket-server\": permission denied": unknown'

在此需要注意的是,整个过程都在 GitLab 上运行,这一点很重要。反正 GitHub 工作流 yaml 文件是这样的:

name: Build and deploy
on:
  - push
  - pull_request

jobs:
  build:
    name: Build
    runs-on: ubuntu-latest
    steps:
      - uses: fusion-engineering/setup-git-credentials@v2
        with:
          credentials: https://${{ secrets.MACHINE_ACCOUNT_ACCESS_TOKEN }}:x-oauth-basic@github.com/

      - name: Setup environment
        shell: bash
        run: |
          echo "::set-env name=GOPATH::${{ github.workspace }}/go"
          echo "::add-path::${{ github.workspace }}/go/bin"

      - name: Install Go
        uses: actions/setup-go@v1
        with:
          go-version: 1.12.4

      - name: Checkout code
        uses: actions/checkout@v2
        with:
          path: go/src/github.com/${{ github.repository }}

      - name: Prepare environment
        run: |
          cd $GOPATH/src/github.com/${{ github.repository }}
          make prepare

      - name: Format code
        run: |
          cd $GOPATH/src/github.com/${{ github.repository }}
          make fmt && git diff --exit-code

      - name: Lint code
        run: |
          cd $GOPATH/src/github.com/${{ github.repository }}
          make lint

      - name: Vet code
        run: |
          cd $GOPATH/src/github.com/${{ github.repository }}
          make vet

      - name: Test code
        run: |
          cd $GOPATH/src/github.com/${{ github.repository }}
          make cover

      - name: Build code
        run: |
          cd $GOPATH/src/github.com/${{ github.repository }}
          make build

      - name: Upload artifact
        uses: actions/upload-artifact@v1
        with:
          name: socket-server
          path: go/src/github.com/${{ github.repository }}/socket-server

  deploy:
    name: Deploy
    runs-on: ubuntu-latest
    needs: [build]
    if: contains(github.ref, 'refs/tags')

    steps:
      - name: Set release version
        run: echo ::set-env name=CI_COMMIT_TAG::${GITHUB_REF/refs\/tags\//}

      - name: Checkout code
        uses: actions/checkout@v2

      - name: Get artifact from build step
        uses: actions/download-artifact@v1
        with:
          name: socket-server

      - name: Set ci auth
        run: echo ::set-env name=CI_AUTH::$(cat ci_auth.json | base64)

      - uses: GoogleCloudPlatform/github-actions/setup-gcloud@master
        with:
          service_account_key: ${{ env.CI_AUTH }}

      - name: Configure gcloud docker authentication
        run: |
          gcloud config set project foo
          gcloud auth configure-docker

      - name: Build, push and deploy container
        run: |
          bash deploy.sh

deploy.sh 文件如下所示:

#!/bin/bash

if [[ -z "${CI_COMMIT_TAG}" ]]; then
    echo "CI_COMMIT_TAG is empty, this stage should not run"
    exit 0
fi

export ENV="stage"

if [[ "$CI_COMMIT_TAG" != "${CI_COMMIT_TAG%-release}" ]]; then
    export ENV="prod"
fi

echo "Current environment: $ENV"

make deploy

Makefile 中的部署步骤如下所示:

deploy:
    ( echo "cat <<EOF" ; cat k8s.yml.template; ) | sh > k8s-${ENV}.yml
    docker build --no-cache \
    --build-arg RELEASE=${CI_COMMIT_TAG} \
    --build-arg ENV=${ENV} \
    -t gcr.io/foo/socket-server:${CI_COMMIT_TAG} .
    docker push gcr.io/foo/socket-server:${CI_COMMIT_TAG}
    gcloud container clusters get-credentials api-${ENV} --zone=europe-west1-b
    kubectl apply -f k8s-${ENV}.yml

Dockerfile 看起来像这样:

FROM alpine:latest as certs
RUN apk --update add ca-certificates

FROM scratch
COPY --from=certs /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt

ARG RELEASE
ARG ENV

ADD ./socket-server /socket-server
ADD ./config.yml /config.yml
ADD ./dbconfig.yml /dbconfig.yml
ADD ./migrations /migrations

ENV SOCKET_SERVER_SENTRY_DSN https://foo@sentry.io/bar
ENV SOCKET_SERVER_SENTRY_RELEASE $RELEASE
ENV SOCKET_SERVER_SENTRY_ENVIRONMENT $ENV

CMD ["/socket-server", "--port", "9345", "--host", ""]

我已经尝试在管道和 Dockerfile (as suggested here) 上使用 chmod +x socket-server。当我在 Dockerfile 中执行此操作时,它会失败并出现以下错误:

Step 14/15 : RUN chmod +x socket-server
 ---> Running in 9c66aef0c35b
OCI runtime create failed: container_linux.go:349: starting container process caused "exec: \"/bin/sh\": stat /bin/sh: no such file or directory": unknown

我是否遗漏了 GitHub 工作流程中的某些内容,或者是否有人看到了我没有看到的内容?感谢您的帮助!

【问题讨论】:

  • 您不会在草稿图像中使用 chmod,这是一个空的基础。在运行 docker build 之前,您需要在构建服务器之前对文件运行 chmod,或者将文件复制到另一个包含 chmod 的基础映像中以在那里修复它。
  • @BMitch 在运行 docker build 之前,我已经尝试在管道上运行chmod +x socket-server(如我的问题中所述)。但不幸的是,这并没有帮助。

标签: docker go github google-kubernetes-engine github-actions


【解决方案1】:

您可以在包含 chmod 二进制文件的另一个阶段中运行 chmod,然后将具有更正权限的文件复制到您的最终基于暂存的阶段:

FROM alpine:latest as certs
RUN apk --update add ca-certificates

FROM alpine:latest as binaries
COPY ./socket-server /socket-server
RUN chmod 755 /socket-server

FROM scratch
COPY --from=certs /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt

COPY --from=binaries /socket-server /
COPY ./config.yml /config.yml
COPY ./dbconfig.yml /dbconfig.yml
COPY ./migrations /migrations

ARG RELEASE
ARG ENV

ENV SOCKET_SERVER_SENTRY_DSN https://foo@sentry.io/bar
ENV SOCKET_SERVER_SENTRY_RELEASE $RELEASE
ENV SOCKET_SERVER_SENTRY_ENVIRONMENT $ENV

CMD ["/socket-server", "--port", "9345", "--host", ""]

请注意,我也已从 ADD 切换到 COPY,因为您不想解压缩二进制文件/yml 文件或从远程 http 服务器拉取它们。而且我还将 ARG 条目移到了您使用它们的位置,以避免过早地破坏缓存(这里不是问题,但会使用 RUN 命令)。

【讨论】:

  • 首先感谢您的回答!我已经尝试过这个 Dockerfile,但我仍然收到错误:'OCI runtime create failed: container_linux.go:345: starting container process caused "exec: \"/socket-server\": permission denied": unknown'。我还在想可能socket-server 可执行文件不存在,所以我在启动deploy.sh 脚本之前将ls 放入管道中,但文件在那里..
  • @Sefa 你的主机是什么,Oracle Linux,RHEL?启用 SELinux?
  • 容器使用 Google Kubernetes Engine 托管在 Google Cloud Platform 上。管道将它们推送到 docker 注册表,kubernetes 尝试使用新推送的版本启动一个新的 pod,我可以看到 pod 无法启动并返回之前声明的错误。
【解决方案2】:

所以我发现上传的工件被管道放在一个文件夹中。所以socket-server 是一个目录,而不是预期的可执行文件。我通过更改它来修复它:

- name: Get artifact from build step
        uses: actions/download-artifact@v1
        with:
          name: socket-server

- name: Get artifact from build step
        uses: actions/download-artifact@v1
        with:
          name: socket-server
          path: .

【讨论】:

    猜你喜欢
    • 2020-01-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-03
    • 2022-01-10
    • 1970-01-01
    • 1970-01-01
    • 2020-05-13
    相关资源
    最近更新 更多