在 Docker 和非 root 用户下使用 GitLab CI Runner 时如何解决权限问题?

How to solve permission problems when using GitLab CI Runner with Docker and non-root user?

我正在使用 GitLab CI Runner 和 Docker。

我的 dockerfile 如下所示:

FROM node:lts-buster-slim

# Install docker dependencies
RUN apt-get update
RUN apt-get install -y --no-install-recommends \
        apt-transport-https \
        build-essential \
        ca-certificates \
        curl \
        gnupg2 \
        dirmngr \
        software-properties-common \
        sudo
# Get Docker GPG key
RUN curl -fsSL https://download.docker.com/linux/debian/gpg | sudo apt-key add -
# Add Docker Repo
RUN sudo add-apt-repository \
  "deb [arch=amd64] https://download.docker.com/linux/debian \
  $(lsb_release -cs) \
  stable"
RUN sudo apt-get update
## Install docker
RUN apt-get install -y --no-install-recommends \
  docker-ce \
  docker-ce-cli \
  containerd.io \
  docker \
  rsync \
  git \
  openssl
### docker-compose
RUN sudo curl -L "https://github.com/docker/compose/releases/download/1.27.4/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
RUN sudo chmod +x /usr/local/bin/docker-compose

RUN groupadd  appuser && \
    useradd -r -g appuser ciuser && \
    usermod -aG docker ciuser

## copy NPM settings
COPY config/.npmrc /root/

## healthcheck and coverage
ADD scripts /usr/local/bin
RUN mkdir -p /info
ADD VERSION_INFO /info/VERSION_INFO
ADD init/.bashrc /root/.bashrc
RUN chown -R ciuser /info && \
    chown -R ciuser /root && \
    chown -R ciuser /home && \
    chmod -R 755 /usr/local

USER ciuser

之前我只是使用 root 用户而不是受限的 ciuser,但是,我的 CI 包括一个测试阶段,需要一个没有 root 权限的用户,这样文件权限测试才能正常工作。

我的 .gitlab-ci.yml 看起来如下:

image: registry.example.com/example/gitlab-javascript-runner:latest

stages:
  - test
  - release
  - publish

before_script:
  - source /root/.bashrc

variables:
  PACKAGE_CMD: export PACKAGE_VERSION=$(node --eval="process.stdout.write(require('./package.json').version)")

cache:
  paths:
    - node_modules/
    - yarn

test-unit:
  stage: test
  tags:
    - docker
  script:
    - npm install && npm run test:cobertura
  coverage: /All\sfiles.*?\s+(\d+.\d+)/
  artifacts:
    reports:
      cobertura: coverage/cobertura-coverage.xml
  allow_failure: false
  only:
    - merge_requests
    - master
    - release

release-gl:
  stage: release
  tags:
    - docker
  script:
    - npm i -g semantic-release && npm i @semantic-release/gitlab
    - semantic-release
  allow_failure: false
  only:
    refs:
      - release

publish-npm:
  stage: publish
  tags:
    - docker
  script:
    - npm publish
  allow_failure: false
  only:
    refs:
      - release

但是,当 运行 semantic-release:

时,为了我的测试正常工作,从 root 用户更改为 ciuser 会导致以下权限错误
$ npm i -g semantic-release && npm i @semantic-release/gitlab
npm WARN checkPermissions Missing write access to /usr/local/lib/node_modules
npm ERR! code EACCES
npm ERR! syscall access
npm ERR! path /usr/local/lib/node_modules
npm ERR! errno -13
npm ERR! Error: EACCES: permission denied, access '/usr/local/lib/node_modules'
npm ERR!  [Error: EACCES: permission denied, access '/usr/local/lib/node_modules'] {
npm ERR!   errno: -13,
npm ERR!   code: 'EACCES',
npm ERR!   syscall: 'access',
npm ERR!   path: '/usr/local/lib/node_modules'
npm ERR! }
npm ERR! 
npm ERR! The operation was rejected by your operating system.
npm ERR! It is likely you do not have the permissions to access this file as the current user
npm ERR! 
npm ERR! If you believe this might be a permissions issue, please double-check the
npm ERR! permissions of the file and its containing directories, or try running
npm ERR! the command again as root/Administrator.
npm ERR! A complete log of this run can be found in:
npm ERR!     /home/ciuser/.npm/_logs/2020-11-23T17_33_17_081Z-debug.log
$ semantic-release
/bin/bash: line 104: semantic-release: command not found
Cleaning up file based variables
00:01
ERROR: Job failed: exit code 1

我尝试在 运行 semantic-release 之前添加以下命令:

- npm set prefix ~/.npm
- PATH="$HOME/.npm/bin:$PATH"
- PATH+="./node_modules/.bin:$PATH"
- source /root/.bashrc

这导致可以找到并执行 semantic-release 的情况,但随后我得到另一个关于 git 的权限错误:

[10:50:23 AM] [semantic-release] › ℹ  Running semantic-release version 17.3.0
[10:50:23 AM] [semantic-release] › ✔  Loaded plugin "verifyConditions" from "@semantic-release/gitlab"
[10:50:23 AM] [semantic-release] › ✔  Loaded plugin "analyzeCommits" from "@semantic-release/commit-analyzer"
[10:50:23 AM] [semantic-release] › ✔  Loaded plugin "publish" from "@semantic-release/gitlab"
[10:50:24 AM] [semantic-release] › ✖  An error occurred while running semantic-release: Error: Command failed with exit code 1: git fetch --tags --update-head-ok https://gitlab-ci-token:[secure]@git.symptoma.com/symptoma/weblate-properties2json-converter +refs/heads/release:refs/heads/release
warning: redirecting to https://git.symptoma.com/symptoma/weblate-properties2json-converter.git/
error: cannot update the ref 'refs/heads/release': unable to append to '.git/logs/refs/heads/release': Permission denied
From https://git.symptoma.com/symptoma/weblate-properties2json-converter
 ! [new branch]      release    -> release  (unable to update local ref)
    at makeError (/home/ciuser/.npm/lib/node_modules/semantic-release/node_modules/execa/lib/error.js:59:11)
    at handlePromise (/home/ciuser/.npm/lib/node_modules/semantic-release/node_modules/execa/index.js:114:26)
    at processTicksAndRejections (internal/process/task_queues.js:93:5)
    at async fetch (/home/ciuser/.npm/lib/node_modules/semantic-release/lib/git.js:120:5)
    at async /home/ciuser/.npm/lib/node_modules/semantic-release/lib/branches/index.js:21:5
    at async pEachSeries (/home/ciuser/.npm/lib/node_modules/semantic-release/node_modules/p-each-series/index.js:8:23)
    at async module.exports (/home/ciuser/.npm/lib/node_modules/semantic-release/lib/branches/index.js:20:3)
    at async run (/home/ciuser/.npm/lib/node_modules/semantic-release/index.js:57:22)
    at async module.exports (/home/ciuser/.npm/lib/node_modules/semantic-release/index.js:260:22)
    at async module.exports (/home/ciuser/.npm/lib/node_modules/semantic-release/cli.js:55:5) {
  shortMessage: 'Command failed with exit code 1: git fetch --tags --update-head-ok https://gitlab-ci-token:[secure]@git.symptoma.com/symptoma/weblate-properties2json-converter +refs/heads/release:refs/heads/release',
  command: 'git fetch --tags --update-head-ok https://gitlab-ci-token:[secure]@git.symptoma.com/symptoma/weblate-properties2json-converter +refs/heads/release:refs/heads/release',
  exitCode: 1,
  signal: undefined,
  signalDescription: undefined,
  stdout: '',
  stderr: 'warning: redirecting to https://git.symptoma.com/symptoma/weblate-properties2json-converter.git/\n' +
    "error: cannot update the ref 'refs/heads/release': unable to append to '.git/logs/refs/heads/release': Permission denied\n" +
    'From https://git.symptoma.com/symptoma/weblate-properties2json-converter\n' +
    ' ! [new branch]      release    -> release  (unable to update local ref)',
  failed: true,
  timedOut: false,
  isCanceled: false,
  killed: false
}
Error: Command failed with exit code 1: git fetch --tags --update-head-ok https://gitlab-ci-token:[secure]@git.symptoma.com/symptoma/weblate-properties2json-converter +refs/heads/release:refs/heads/release
warning: redirecting to https://git.symptoma.com/symptoma/weblate-properties2json-converter.git/
error: cannot update the ref 'refs/heads/release': unable to append to '.git/logs/refs/heads/release': Permission denied
From https://git.symptoma.com/symptoma/weblate-properties2json-converter
 ! [new branch]      release    -> release  (unable to update local ref)
    at makeError (/home/ciuser/.npm/lib/node_modules/semantic-release/node_modules/execa/lib/error.js:59:11)
    at handlePromise (/home/ciuser/.npm/lib/node_modules/semantic-release/node_modules/execa/index.js:114:26)
    at processTicksAndRejections (internal/process/task_queues.js:93:5)
    at async fetch (/home/ciuser/.npm/lib/node_modules/semantic-release/lib/git.js:120:5)
    at async /home/ciuser/.npm/lib/node_modules/semantic-release/lib/branches/index.js:21:5
    at async pEachSeries (/home/ciuser/.npm/lib/node_modules/semantic-release/node_modules/p-each-series/index.js:8:23)
    at async module.exports (/home/ciuser/.npm/lib/node_modules/semantic-release/lib/branches/index.js:20:3)
    at async run (/home/ciuser/.npm/lib/node_modules/semantic-release/index.js:57:22)
    at async module.exports (/home/ciuser/.npm/lib/node_modules/semantic-release/index.js:260:22)
    at async module.exports (/home/ciuser/.npm/lib/node_modules/semantic-release/cli.js:55:5) {
  shortMessage: 'Command failed with exit code 1: git fetch --tags --update-head-ok https://gitlab-ci-token:[secure]@git.symptoma.com/symptoma/weblate-properties2json-converter +refs/heads/release:refs/heads/release',
  command: 'git fetch --tags --update-head-ok https://gitlab-ci-token:[secure]@git.symptoma.com/symptoma/weblate-properties2json-converter +refs/heads/release:refs/heads/release',
  exitCode: 1,
  signal: undefined,
  signalDescription: undefined,
  stdout: '',
  stderr: 'warning: redirecting to https://git.symptoma.com/symptoma/weblate-properties2json-converter.git/\n' +
    "error: cannot update the ref 'refs/heads/release': unable to append to '.git/logs/refs/heads/release': Permission denied\n" +
    'From https://git.symptoma.com/symptoma/weblate-properties2json-converter\n' +
    ' ! [new branch]      release    -> release  (unable to update local ref)',
  failed: true,
  timedOut: false,
  isCanceled: false,
  killed: false
}

是否可以在不同的阶段使用不同的用户,或者对于 运行 具有受限用户的测试阶段和具有 root 用户的发布阶段还有哪些其他选项可用?

我终于解决了这个问题:

  • 正在从 Dockerfile 中删除 USER ciuser,以便运行器再次从 root 用户开始
  • 按如下方式更改测试命令 sudo -H -u ciuser bash -c "npm install && npm run test:cobertura" 以便它由 ciuser 执行,如本 post.
  • 中所述

在 Dockerfile 中删除 USER <username> 对我有用。