尝试通过 Gitlab 部署到 Digital Ocean 时出现 SSH 错误 CI/CD

SSH error when trying to deploy to Digital Ocean via Gitlab CI/CD

晚上好, 我正在尝试通过 Gitlab CI/CD 管道部署到 Digital Ocean,但是当我 运行 管道时,我得到一个: "chmod: /root/.ssh/id_rsa: 没有那个文件或目录 $ chmod og= ~/.ssh/id_rsa 清理基于文件的变量 00:00 错误:作业失败:退出代码 1".

出于某种原因,它没有使用我为部署创建的用户,而是使用 root,但是当我使用 cat 命令查看服务器中的 ssh 密钥时,它显示在 root 和部署者用户中。 下面是我的 .yml 文件。

before_script:
  - echo $PATH
  - pwd
  - whoami 
  - mkdir -p ~/.ssh
  - cd ~/.ssh
  - echo "$SSH_PRIVATE_KEY" | tr -d '\r' > id_rsa
  - echo "$SSH_PUBLIC_KEY" | tr -d '\r' > id_rsa.pub
  - chmod 700 id_rsa id_rsa.pub
  - cp id_rsa.pub authorized_keys
  - cp id_rsa.pub known_hosts
  - ls -ld *
  - cd -

stages:
  - build
  - publish
  - deploy

variables:
  TAG_LATEST: $CI_REGISTRY_IMAGE/$CI_COMMIT_REF_NAME:latest
  TAG_COMMIT: $CI_REGISTRY_IMAGE/$CI_COMMIT_REF_NAME:$CI_COMMIT_SHORT_SHA

build:
  image: node:latest
  stage: build
  script:
    - npm install
    - echo   "ACCOUNT_SID=$ACCOUNT_SID" >> .env
    - echo   "AUTH_TOKEN=$AUTH_TOKEN" >> .env
    - echo   "API_KEY=$API_KEY" >> .env
    - echo   "API_SECRET=$API_SECRET" >> .env
    - echo   "PHONE_NUMBER=$PHONE_NUMBER" >> .env
    - echo    "sengrid_api=$sengrid_api" >> .env

publish:
  image: docker:latest
  stage: publish
  services:
    - docker:dind
  script:
    - docker build . -t $TAG_COMMIT -t $TAG_LATEST 
    - docker login -u gitlab-ci-token -p $CI_BUILD_TOKEN $CI_REGISTRY
    - docker push $TAG_COMMIT
    - docker push $TAG_LATEST

deploy:
  image: alpine:latest
  stage: deploy
  tags:
    - deployment
  script:
    - whoami
    - uname -a
    - echo "user $SERVER_USER"
    - echo "ip $SERVER_IP"
    - echo "id_rsa $ID_RSA"
    - (which ifconfig) || (apt install net-tools)
    - /sbin/ifconfig
    - touch blah
    - find .
    - apk update && apk add openssh-client
    - ssh  -o StrictHostKeyChecking=no $SERVER_USER@$SERVER_IP "docker login -u gitlab-ci-token -p $CI_BUILD_TOKEN $CI_REGISTRY"
    - ssh  -o StrictHostKeyChecking=no $SERVER_USER@$SERVER_IP "docker pull $TAG_COMMIT"
    - ssh  -o StrictHostKeyChecking=no $SERVER_USER@$SERVER_IP "docker container rm -f my-app || true"
    - ssh  -o StrictHostKeyChecking=no $SERVER_USER@$SERVER_IP "docker run -d -p 80:3000 --name my-app $TAG_COMMIT"
  environment:
    name: production
    url: http://167.172.225.124
  only:
    - master

您所遵循的 DigitalOcean tutorial 的先决条件包括一个 sudo 非根用户,以及一个启用了容器注册表的 GitLab 实例上的用户帐户。

通过script.deb.sh安装的gitlab-runner服务应该需要非root用户的密码才能继续。

它涉及创建一个专用于部署任务的用户,稍后配置 CI/CD 管道以使用该用户登录服务器。

这意味着 gitlab-ci 不应该被 root 执行,这在任何阶段都不涉及。

经过几个小时的工作和错误:

cat id_rsa.pub >> authorized_keys:修复了权限被拒绝(public 密钥,密码)错误 ssh-keyscan gitlab.com >> authorized_keys: 这个密钥修复了连接被拒绝的错误。 下面是最终的 .yml 文件。

# ssh-keyscan gitlab.com >> authorized_keys: use this command to add gitlab ssh keys to sever. Run on server terminal
# cat id_rsa.pub >> authorized_keys Run this command on the sever on the terminal. 
# Both COMMANDS ABOVE ARE necessary.

stages:
  - build
  - publish
  - deploy

variables:
  TAG_LATEST: $CI_REGISTRY_IMAGE/$CI_COMMIT_REF_NAME:latest
  TAG_COMMIT: $CI_REGISTRY_IMAGE/$CI_COMMIT_REF_NAME:$CI_COMMIT_SHORT_SHA

build:
  image: node:latest
  stage: build
  script:
    - npm install
    - echo   "ACCOUNT_SID=$ACCOUNT_SID" >> .env
    - echo   "AUTH_TOKEN=$AUTH_TOKEN" >> .env
    - echo   "API_KEY=$API_KEY" >> .env
    - echo   "API_SECRET=$API_SECRET" >> .env
    - echo   "PHONE_NUMBER=$PHONE_NUMBER" >> .env
    - echo    "sengrid_api=$sengrid_api" >> .env

publish:
  image: docker:latest
  stage: publish
  services:
    - docker:dind
  script:
    - docker build . -t $TAG_COMMIT -t $TAG_LATEST 
    - docker login -u gitlab-ci-token -p $CI_BUILD_TOKEN $CI_REGISTRY
    - docker push $TAG_COMMIT
    - docker push $TAG_LATEST

deploy:
  image: ubuntu:latest
  stage: deploy
  tags:
    - deployment
  before_script:
    ##
  ## Install ssh-agent if not already installed, it is required by Docker.
  ## (change apt-get to yum if you use an RPM-based image)
  ##
  - 'which ssh-agent || ( apt-get update -y && apt-get install openssh-client git -y )'

  ##
  ## Run ssh-agent (inside the build environment)
  ##
  - eval $(ssh-agent -s)
  ##
  ## Create the SSH directory and give it the right permissions
  ##
  - mkdir -p ~/.ssh
  - chmod 700 ~/.ssh
  ##
  ## Add the SSH key stored in SSH_PRIVATE_KEY variable to the agent store
  ## We're using tr to fix line endings which makes ed25519 keys work
  ## without extra base64 encoding.
  ## https://gitlab.com/gitlab-examples/ssh-private-key/issues/1#note_48526556
  ##
  - echo "$SSH_PRIVATE_KEY" | tr -d '\r' > ~/.ssh/id_rsa
  - echo "$SSH_PUBLIC_KEY" | tr -d '\r' > ~/.ssh/id_rsa.pub
  - chmod 600 ~/.ssh/*
  - chmod 644 ~/.ssh/*.pub
  - ssh-add
 

  ##
  ## Use ssh-keyscan to scan the keys of your private server. Replace gitlab.com
  ## with your own domain name. You can copy and repeat that command if you have
  ## more than one server to connect to.
  ##
  - ssh-keyscan gitlab.com >> ~/.ssh/known_hosts
  - chmod 644 ~/.ssh/known_hosts
  - ls -ld ~/.ssh/*
  - cat ~/.ssh/*
  ##
  ## Alternatively, assuming you created the SSH_SERVER_HOSTKEYS variable
  ## previously, uncomment the following two lines instead.
  ##
  #- echo "$SSH_SERVER_HOSTKEYS" > ~/.ssh/known_hosts'
  #- chmod 644 ~/.ssh/known_hosts

  ##
  ## You can optionally disable host key checking. Be aware that by adding that
  ## you are suspectible to man-in-the-middle attacks.
  ## WARNING: Use this only with the Docker executor, if you use it with shell
  ## you will overwrite your user's SSH config.
  ##
  #- '[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config'

  ##
  ## Optionally, if you will be using any Git commands, set the user name and
  ## email.
  ##

  script:
    
    - ssh -v -o StrictHostKeyChecking=no $SERVER_USER@$SERVER_IP "docker login -u gitlab-ci-token -p $CI_BUILD_TOKEN $CI_REGISTRY"
    - ssh  -o StrictHostKeyChecking=no $SERVER_USER@$SERVER_IP "docker pull $TAG_COMMIT"
    - ssh  -o StrictHostKeyChecking=no $SERVER_USER@$SERVER_IP "docker container rm -f my-app || true"
    - ssh  -o StrictHostKeyChecking=no $SERVER_USER@$SERVER_IP "docker run -d -p 80:3000 --name my-app $TAG_COMMIT"
  environment:
    name: production
    url: http://167.172.225.124
  only:
    - master