如何在AWS上使用子模块自动部署git存储库?

时间:2017-03-10 07:20:15

标签: git github git-submodules aws-code-deploy

我的git存储库中有一个子模块,我的目录结构就像,

app
  -- folder1
  -- folder2
  -- submodule @5855

我已使用autodeploy服务在AWS上部署了我的代码。 现在,在服务器上,我在父目录中有代码,但子模块目录是空的。

Q1)如何在子模块中获取数据。我在服务器上的存储库不是git存储库。我是否需要先将其转换为git repo,然后运行submodule命令才能获得它?

Q2)我如何自动化子模块部署?

由于

8 个答案:

答案 0 :(得分:8)

这是对我有用的

我们将重新初始化git存储库,然后在部署的构建阶段触发子模块克隆,从本质上打补丁以支持codepipeline / codebuild中的子模块

  • 为您的github帐户生成一个新的SSH密钥,如果使用组织,则可能要创建一个部署用户
  • 使用aws ssm put-parameter --name build_ssh_key --type String --value "$(cat id_rsa)"将此ssh密钥存储在aws参数存储区中,最好使用SecureString而不是String,但是我遵循的指南只是使用了string,所以我不确定命令行是否需要任何额外的参数
  • 进入IAM并授予您的CodePipeline用户对您的paramstore的读取权限,我刚刚授予对SSM的读取权限

然后使您的buildspec.yml如下所示:

version: 0.2

env:
  parameter-store:
    build_ssh_key: "build_ssh_key"

phases:
  install:
    commands:
      - mkdir -p ~/.ssh
      - echo "$build_ssh_key" > ~/.ssh/id_rsa
      - chmod 600 ~/.ssh/id_rsa
      - ssh-keygen -F github.com || ssh-keyscan github.com >>~/.ssh/known_hosts
      - git config --global url."git@github.com:".insteadOf "https://github.com/"
      - git init
      - git remote add origin <Your Repo url here using the git protocol>
      - git fetch
      - git checkout -t origin/master
      - git submodule init
      - git submodule update --recursive
  build:
    commands:
      - echo '...replace with real build commands...'

artifacts:
  files:
    - '**/*'

答案 1 :(得分:6)

我自己遇到了这个问题,由于@ matt-bucci提出了很棒的建议,我得以提出一个健壮的解决方案。

我的特定用例略有不同-我正在使用Lambda层来减少lambda冗余,但仍需要将这些层作为子模块包含在Lambda函数存储库中,以便CodeBuild可以构建和测试PR。我使用CodePipeline来协助持续交付-所以我需要一个可以同时与CodePipeline和CodeBuild一起使用的系统

  1. 我创建了一个新的SSH密钥,供these instructions之后的“机器用户”使用。在这种情况下,我使用的是计算机用户,因此不需要为每个项目以及潜在的多个私有子模块支持生成新的ssh密钥

  2. 我将私钥作为SecureString存储在AWS Parameter Store中。这实际上并没有改变CodeBuild中的任何内容,因为它足够聪明,只知道如何解密密钥

  3. 我为AWS托管属性赋予了“ codebuild”角色:AmazonSSMReadOnlyAccess-允许CodeBuild访问私钥

  4. 我使用@ matt-bucci建议的一堆命令以及一些新命令来制作buildspec.yml文件

# This example buildspec will enable submodules for CodeBuild projects that are both 
# triggered directly and via CodePipeline
#
# This buildspec is designed with help from Stack Overflow: 
# https://stackoverflow.com/questions/42712542/how-to-auto-deploying-git-repositories-with-submodules-on-aws
version: 0.2  # Always use version 2
env:
  variables:
    # The remote origin that will be used if building through CodePipeline
    remote_origin: "git@github.com:your/gitUri"
  parameter-store:
    # The SSH RSA Key used by our machine user
    ssh_key: "ssh_key_name_goes_here"
phases:
  install:
    commands:
      # Add the "machine user's" ssh key and activate it - this allows us to get private (sub) repositories
      - mkdir -p ~/.ssh                   # Ensure the .ssh directory exists
      - echo "$ssh_key" > ~/.ssh/ssh_key  # Save the machine user's private key
      - chmod 600 ~/.ssh/ssh_key          # Adjust the private key permissions (avoids a critical error)
      - eval "$(ssh-agent -s)"            # Initialize the ssh agent
      - ssh-add ~/.ssh/ssh_key            # Add the machine user's key to the ssh "keychain"
      # SSH Credentials have been set up. Check for a .git directory to determine if we need to set up our git package
      - |
        if [ ! -d ".git" ]; then
          git init                                              # Initialize Git
          git remote add origin "$remote_origin"                # Add the remote origin so we can fetch
          git fetch                                             # Get all the things
          git checkout -f "$CODEBUILD_RESOLVED_SOURCE_VERSION"  # Checkout the specific commit we are building
        fi
      # Now that setup is complete, get submodules
      - git submodule init
      - git submodule update --recursive
      # Additional install steps... (npm install, etc)
  build:
    commands:
      # Build commands...
artifacts:
  files:
    # Artifact Definitions...

此安装脚本执行三个独立的步骤

  1. 它会安装并启用用于访问私有存储库的ssh私有密钥

  2. 它确定是否存在.git文件夹-如果没有,则脚本将初始化git并检出正在构建的 exact 提交。 注意:根据AWS文档,不能{em>保证出现在$CODEBUILD_RESOLVED_SOURCE_VERSION envar中,而不能在CodePipeline构建中出现。但是,我没有看到失败

  3. 最后,它实际上获得了子模块

显然,这不是解决此问题的好方法。但是,鉴于CodePipeline的(不必要)限制,这是我能想到的最好的方法。此过程的副作用是“源” CodePipeline阶段完全没有用,因为我们只是覆盖已存档的源文件-它仅用于侦听对存储库的更改

人们要求更好的功能已有2年以上: https://forums.aws.amazon.com/thread.jspa?threadID=248267

编辑于2019年1月23日

我(以艰难的方式)意识到我以前的回答不支持CodePipeline构建,仅直接通过CodeBuild运行。当CodeBuild响应GitHub Webhook时,它将克隆整个GitHub存储库,包括.git文件夹

但是,当使用CodePipeline时,“源”操作将克隆存储库,签出适当的分支,然后在没有.git文件夹的情况下原始文件 。这意味着我们必须初始化github存储库才能访问子模块

答案 2 :(得分:4)

整天紧张了一下之后,我发现了一个简单的解决方案(用于代码管道),不需要在buildspec中使用任何SSH密钥。我正在使用Bitbucket,但我认为这将对其他提供商有用。我还通过https克隆了我的子模块,我不确定这是否是必需条件。

  1. 配置源以对存储库进行 完整克隆 。这将传递您需要的git元数据。 Source configuration

  2. 配置您的构建角色以添加客户管理的UseConnection权限,以使您的构建操作可以访问为源配置的凭据。来自AWS的文档在这里: https://docs.aws.amazon.com/codepipeline/latest/userguide/troubleshooting.html#codebuild-role-connections

  3. 设置环境以包括 git-credential-helper:是,然后在buildspec.yml中克隆子模块:

enter image description here

就是这样!可以使用子模块进行构建,而不必为要使用的每个子模块进行一堆关键配置。

如果最终对人们有用的话,也许是对文档的很好补充。

答案 3 :(得分:3)

@MattBucci答案有效时,有一个警告,您只能拉特定的分支,而不能拉子模块正在使用的特定提交。

为了处理这种情况(在使用子模块时可能会发生),需要做很多事情:

1)创建一个具有以下内容的git pre-commit钩子:

#!/bin/bash

#   This file is used in post-commit hook
#   if .commit exists you know a commit has just taken place but a post-commit hasn't run yet
#
touch .commit

如果已经有一行,则可以在开头添加该行。

2)使用以下内容创建一个git post-commit钩子:

#!/bin/bash


DIR=$(git rev-parse --show-toplevel);

if [[ -e $DIR/.commit ]]; then
    echo "Generating submodule integrity file"
    rm .commit

    SUBMODULE_TRACKING_FILE=$DIR/.submodule-hash
    MODULE_DIR=module
    #   Get submodule hash, this will be used by AWS Code Build to pull the correct version.
    #   AWS Code Build does not support git submodules at the moment
    #   https://forums.aws.amazon.com/thread.jspa?messageID=764680#764680
    git ls-tree $(git symbolic-ref --short HEAD) $MODULE_DIR/ | awk '{ print $3 }' > $SUBMODULE_TRACKING_FILE

    git add $SUBMODULE_TRACKING_FILE
    git commit --amend -C HEAD --no-verify
fi

exit 0

此钩子会将当前提交哈希放入.submodule-hash文件中,该文件需要提交到版本控制

3)转到您的AWS Code构建项目

Developer Tools > CodeBuild > Build projects > YOUR_PROJECT > Edit Environment

添加一个名为GIT_KEY的环境变量,该值将是基于64位编码的ssh密钥。 (没有换行符,否则它将不起作用)。

您可以online对其进行转换,也可以使用任何工具或编程语言。

enter image description here

4)。在您的buildspec.yml上添加一个pre_build脚本。

version: 0.2

phases:
  pre_build:
    commands:
      - bash build/aws-pre-build.sh
...

5)创建具有以下内容的build/aws-pre-build.sh

#!/bin/bash

set -e

#   Get root path
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && cd .. && pwd )"

MODULE_HASH=$(cat $DIR/.submodule-hash);
GIT_HOST=bitbucket.org
MODULE_DIR=module
REPO=user/repo.git


if [[ ! -d ~/.ssh ]]; then
    mkdir ~/.ssh
fi

if [[ ! -f ~/.ssh/known_hosts ]]; then
    touch ~/.ssh/known_hosts
fi

#   Base64 decode private key, and save it to ~/.ssh/git
echo "- Adding git private key"

echo $GIT_KEY | base64 -d > ~/.ssh/git

#   Add correct permissions to key
chmod 600 ~/.ssh/git

#   Add $GIT_HOST to ssh config
echo "- Adding ssh config file"

cat > ~/.ssh/config <<_EOF_
Host $GIT_HOST
    User git
    IdentityFile ~/.ssh/git
    IdentitiesOnly yes
_EOF_

#   Check if host is present in known_hosts
echo "- Checking $GIT_HOST in known_hosts"

if ! ssh-keygen -F $GIT_HOST > /dev/null; then
    echo "- Adding $GIT_HOST to known hosts"
    ssh-keyscan -t rsa $GIT_HOST >> ~/.ssh/known_hosts
fi

#   AWS Code build does not send submodules, remove the empty folder
rm -rf $MODULE_DIR

# Clone submodule in the right folder
git clone git@$GIT_HOST:$REPO $MODULE_DIR

# cd to submodule
cd $DIR/$MODULE_DIR

# Checkout the right commit
echo "- Checking out $MODULE_HASH"

git checkout $MODULE_HASH


其他

如果在进行AWS Code Build之前还有其他步骤(例如,位桶管道或类似工具),则可以检查实际的git子模块哈希是否与生成的文件中的哈希匹配:.submodule-hash

如果不匹配,则表示曾经推送过,没有git钩子。

#!/bin/bash

$MODULE_DIR=module

echo "- Checking submodules integrity"

SUBMODULE_TRACKING_FILE=.submodule-hash


#   Check submodule hash, this will be used by AWS Code Build to pull the correct version.
#   AWS Code Build does not support git submodules at the moment
#   https://forums.aws.amazon.com/thread.jspa?messageID=764680#764680

#   Git submodule actual hash
SUBMODULE_HASH=$(git ls-tree $(git symbolic-ref --short HEAD) $MODULE_DIR/ | awk '{ print $3 }')

if [[ ! -e $SUBMODULE_TRACKING_FILE ]]; then

    echo "ERROR: $SUBMODULE_TRACKING_FILE file not found."
    submoduleError

    exit 1
fi

#   Custom submodule hash - The is used by AWS Code Build
SUBMODULE_TRACKING_FILE_HASH=$(cat $SUBMODULE_TRACKING_FILE)

if [[ "$SUBMODULE_TRACKING_FILE_HASH" != "$SUBMODULE_HASH"  ]]; then

    echo "ERROR: $SUBMODULE_TRACKING_FILE file content does not match submodule hash: $SUBMODULE_HASH"

    echo -e "\tYou should have pre-commit && post-commit hook enabled or update $SUBMODULE_TRACKING_FILE manually:"
    echo -e "\tcmd: git ls-tree $(git symbolic-ref --short HEAD) $MODULE_DIR/ | awk '{ print \$3 }' > $SUBMODULE_TRACKING_FILE"

    exit 1
fi

注意:您还可以在AWS Code Build之前在管道上创建该文件,创建提交,对其进行标记并推送,以便AWS Code Build管道开始。

git ls-tree $(git symbolic-ref --short HEAD) module/ | awk '{ print \$3 }' > .submodule-hash

答案 4 :(得分:2)

我在AWS CodeBuild上遇到了同样的问题。我像下面的图像一样勾选Use Git submodules,以更新我的submodule

enter image description here

当我运行构建时,出现以下错误,

CLIENT_ERROR: Submodule error error creating SSH agent: "SSH agent requested but SSH_AUTH_SOCK not-specified" for primary source and source version refs/heads/dev

因此,我搜索了以上错误,并从AWS论坛获得了这个DOWNLOAD_SOURCE Fails with Git submodules线程。他们已经提到,

子模块必须配置为https而不是ssh。

我认为这没有用,将submodule设置为ssh的人会发生什么。我也做了同样的事情,这是我的.gitmodules文件。

[submodule "common"]
    path = common
    url = git@bitbucket.org:organization_id/common.git

真的,我不想将其更改为https。然后,我从中发现了这篇Working with Git Submodules in CodePipeline文章。我想想像一下我为解决此问题所做的工作,并且在该article中没有提到一个错误。让我们以更安全的方式进行操作。


首先转到AWS Key Management Service (KMS)并转到Customer managed keys部分,然后单击Create key创建密钥。

  1. 单击Symmetric,然后单击Next

enter image description here

  1. 使用任何名称(例如:-bitbucket-credentials)创建Alias,然后单击Next

enter image description here

  1. 很可能您已经有一个AWS Role来配置Developer Tools on AWS中的任何一个,因此在我的情况下,我为AWS CodeBuild创建了一个AWS Role调用ecsCodeBuildRole并给出Define key administrative permissions,然后点击Next

enter image description here

  1. 接下来为您的Define key usage permissions输入AWS Role,然后单击Next

enter image description here

  1. 最后查看您到目前为止所做的事情,然后单击Finish创建 CMK

enter image description here

  1. 您可以按以下方式进行查看。

enter image description here


因此AWS Key Management Service (KMS)部分已经完成,现在转到AWS Systems Manager并找到Parameter Store部分。点击Create parameter

  1. 只需将其命名为id_rsa,然后将类似下面的内容放入

enter image description here enter image description here

  1. 对于value部分,只需在终端中运行cat ~/.ssh/id_rsa命令,您将获得如下输出。将其添加到value部分。
-----BEGIN RSA PRIVATE KEY-----
qdjbXp+42VTnccC7pxOZcofomfwGXPWuqcv99sQEPtToODvGIxWoooJUpb6qMIWY
1zccEuwAhmqcPvpsJyWhcctZB/wWglNvViZcOYjrQ8HBUBKJT8pF
-----END RSA PRIVATE KEY-----
  1. 创建另一个参数,并将其命名为id_rsa.pub。遵循与上述相同的步骤。

  2. 对于value部分,只需在终端中运行cat ~/.ssh/id_rsa.pub命令,您将获得如下输出。将其添加到value部分。

ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDGtf8jjkogWxRGNGjJlOZ1G+pWExgDOdA5wVML6TMTT2YtvhPJD60nPx5TfA8zRzGWubwrPp40SPAhSs5wiAAg38HlS4pz9X wasdkiller@wasdkiller

根据我的研究(也许我错了,请纠正我),我没有其他方法可以将ssh凭据传递给AWS CodeBuild,而无需付出太多努力。因此,我像这样手动更改了buildspec.yml文件。

version: 0.2

env:
  parameter-store:
    ssh_key: id_rsa
    ssh_pub: id_rsa.pub

phases:
  install:
    commands:
      - mkdir -p ~/.ssh
      - echo "$ssh_key" > ~/.ssh/id_rsa   
      - echo "$ssh_pub" > ~/.ssh/id_rsa.pub
      - chmod 600 ~/.ssh/id_rsa
      - eval "$(ssh-agent -s)"
      - git submodule update --init --recursive

当您继续时,您肯定会遇到以下错误,

Decrypted Variables Error: AccessDeniedException: User: arn:aws:sts::organization_id:assumed-role/ecsCodeBuildRole/AWSCodeBuild-12896abb-bdcf-4cfc-a12b-bcf30d6e96ab is not authorized to perform: ssm:GetParameters on resource: arn:aws:ssm:ap-southeast-2:organization_id:parameter/wasd status code: 400, request id: 23b94bc2-961e-4d86-9b73-d16e3bda357c

它会询问您ssm:GetParameters的权限,只需附加AmazonSSMReadOnlyAccess策略或使用ssm:GetParameters权限手动创建策略并将其附加到您的AWS Role,解决这个问题。

答案 5 :(得分:0)

如果将CodeCommit用作存储库,则不需要

SSH。使用AWS CLI Credential Helper并通过https进行克隆。

git config --global credential.helper '!aws codecommit credential-helper $@'
git config --global credential.UseHttpPath true
git clone https://git-codecommit.[region].amazonaws.com/v1/repos/[repo]

答案 6 :(得分:0)

从发现子模块问题到现在已经很久了。但是aws无法修复它。因此,codepipeline无法将.git目录发送到codebuild。因此,我们必须发明新的双锥齿轮,我的解决方法是在buildspec.yml预构建命令中

rm -rf $PWD/*
git clone --depth 1 https://<REPO NAME>  -b develop .
git submodule update --init --recursive

AWS快点,因为我们的团队正在考虑移回github。

答案 7 :(得分:0)

借用@MattBucci和@JoshuaEvans的概念。这就是我们所做的。由于ssh的严格访问/安全问题,我们无法在管道中安装git。因此,我们最终通过HTTP进行了此操作。

  1. 我创建了一个新的Github个人访问令牌
  2. 我将PAT作为以下文件存储在AWS Secrets Manager中: SecureString。这实际上并没有改变任何东西 CodeBuild,因为它足够聪明,只知道如何解密 键
  3. 我授予了“代码构建”角色,供机密管理器读取
  4. 我使用一堆命令制作了buildspec.yml文件 @ matt-bucci和@JoshuaEvans以及一些新的建议
version: 0.2
env:
    variables:
      token: " token "
    secrets-manager:
      personalAccessToken: $personalAccessTokenPath
phases:
    install:
      runtime-versions:
        nodejs: 12
      commands:
          - cd <to the folder where you want the submodules>
          - wget --header="Authorization:$token$personalAccessToken" --content-disposition  https://github.com/uri/zipball/$branch/
          - unzip project*.zip -d project-folder
          - rm -rf project*.zip
          - cd project-folder
          - mv project*/* .
          - rm -rf project*
          - cd <back to your base folder where the buildspec is>
    pre_build:
      commands:
        - xxx
    build:
      commands:
        - xxx
    post_build:
      commands:
        - xxx
artifacts:
    files:
      - '**/*'
    base-directory: dist

希望这会有所帮助!