用于在 AWS EC2 中构建和部署 docker 映像的 CI/CD 脚本

Posted

技术标签:

【中文标题】用于在 AWS EC2 中构建和部署 docker 映像的 CI/CD 脚本【英文标题】:CI/CD script for build & deploy docker image in aws EC2 【发布时间】:2021-12-08 11:06:45 【问题描述】:

我可以使用此 CI/CD 配置构建、推送(到 gitlab 注册表)和部署映像(到 aws EC2)吗?

stages:
  - build
  - deploy

build:
  # Use the official docker image.

  image: docker:latest
  stage: build
  services:
    - docker:dind
  before_script:
    - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
  # Default branch leaves tag empty (= latest tag)
  # All other branches are tagged with the escaped branch name (commit ref slug)
  script:
    - |
      if [[ "$CI_COMMIT_BRANCH" == "$CI_DEFAULT_BRANCH" ]]; then
        tag=""
        echo "Running on default branch '$CI_DEFAULT_BRANCH': tag = 'latest'"
      else
        tag=":$CI_COMMIT_REF_SLUG"
        echo "Running on branch '$CI_COMMIT_BRANCH': tag = $tag"
      fi
    - docker build --pull -t "$CI_REGISTRY_IMAGE$tag" .
    - docker push "$CI_REGISTRY_IMAGE$tag"
  # Run this job in a branch where a Dockerfile exists

deploy:
  stage: deploy
  before_script:
    - echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add -
    - mkdir -p ~/.ssh
    - chmod 700 ~/.ssh
  script:
    - ssh -o StrictHostKeyChecking=no ubuntu@18.0.0.82 "sudo docker login -u $CI_REGISTRY_USER --password-stdin $CI_REGISTRY; sudo docker pull $CI_REGISTRY_IMAGE$tag; cd /home/crud_app; sudo docker-compose up -d"
  after_script:
    - sudo docker logout

  rules:
    - if: $CI_COMMIT_BRANCH
      exists:
        - Dockerfile

脚本构建成功后,部署失败。

(构建成功)

(部署失败)

必须构建配置并部署映像

【问题讨论】:

该行出错:echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add - 关于最后一个错误,在“脚本后”中,它说没有找到sudo。您是否尝试将其从 sudo docker logout 中删除? 【参考方案1】:

有几个错误,但整体管道看起来不错。

    您不能在没有运行代理的情况下使用ssh-add 如果之后您明确忽略将存储在known_hosts 下的密钥,为什么还要手动创建 .ssh 文件夹? 使用StrictHostKeyChecking=no 很危险,完全不推荐。

before_script 上添加以下内容:

before_script:
    - eval `ssh-agent`
    - echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add -
    - mkdir -p ~/.ssh
    - ssh-keyscan -H 18.0.0.82 >> ~/.ssh/known_hosts

另外,不要在您的ubuntu 用户上使用sudo,最好将其添加到docker 组或通过SSH 连接到docker 组中的用户。


如果您的 EC2 实例中还没有 docker 组,现在是配置它的好时机:

访问您的 EC2 实例并创建 docker 组:

$ sudo groupadd docker

ubuntu 用户添加到docker 组:

$ sudo usermod -aG docker ubuntu

现在将您的 script 更改为:

script:
    - echo $CI_REGISTRY_PASSWORD > docker_password
    - scp docker_password ubuntu@18.0.0.82:~/tmp/docker_password
    - ssh ubuntu@18.0.0.82 "cat ~/tmp/docker_password | docker login -u $CI_REGISTRY_USER --password-stdin $CI_REGISTRY; docker pull $CI_REGISTRY_IMAGE$tag; cd /home/crud_app; docker-compose up -d; docker logout; rm -f ~/tmp/docker_password"

另外,请记住,在 after_script 中,您不在 EC2 实例中,而是在运行器映像中,因此您不需要 logout,但最好杀死 SSH 代理。

最后的工作

deploy:
  stage: deploy
  before_script:
    - eval `ssh-agent`
    - echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add -
    - mkdir -p ~/.ssh
    - ssh-keyscan -H 18.0.0.82 >> ~/.ssh/known_hosts
  script:
    - echo $CI_REGISTRY_PASSWORD > docker_password
    - scp docker_password ubuntu@18.0.0.82:~/tmp/docker_password
    - ssh ubuntu@18.0.0.82 "cat ~/tmp/docker_password | docker login -u $CI_REGISTRY_USER --password-stdin $CI_REGISTRY; docker pull $CI_REGISTRY_IMAGE$tag; cd /home/crud_app; docker-compose up -d; docker logout; rm -f ~/tmp/docker_password"
  after_script:
    - kill $SSH_AGENT_PID
    - rm docker_password
  rules:
    - if: $CI_COMMIT_BRANCH
      exists:
        - Dockerfile

【讨论】:

请解释一下这个脚本我没明白这里发生了什么“-scp docker_password ubuntu@18.0.0.82:~/tmp/docker_password” 您试图通过stdin 在登录中传递密码,但标准输入上没有任何内容。所以我把密码写在文件docker_password中,然后我用scp把它复制到EC2实例上。然后在登录时,我使用cat 读取该文件的内容,并将输出通过管道传送到docker login 命令。

以上是关于用于在 AWS EC2 中构建和部署 docker 映像的 CI/CD 脚本的主要内容,如果未能解决你的问题,请参考以下文章

Docker和AMI之间的区别

AWS - ECS - 如何在现有 ECS(带有 1 个 EC2)实例上重新部署更新的 Docker 映像?

AWS EC2+Docker+JMeter构建分布式负载测试基础架构

具有 Auto Scaling 与弹性容器服务 (ECS) 的 AWS EC2 - Docker

AWS opsworks docker 服务发现

在 Gitlab CI 构建中,我无法通过私钥 ssh 进入 AWS EC2