Как автоматически развертывать репозитории git с субмодулями на AWS?

У меня есть подмодуль в моем репозитории git, и моя структура каталога похожа на

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

Я развернул свой код на AWS, используя службу autodeploy. Теперь на сервере у меня есть код в родительском каталоге, но каталоги подмодулей пусты.

Q1) Как получить данные в подмодулях. Мой репозиторий на сервере не репозиторий git. Нужно ли сначала преобразовать его в git repo, а затем запустить команды submodule, чтобы получить его?

Q2) Как я могу автоматизировать развертывание подмодуля?

Спасибо

Ответ 1

Вот что у меня сработало

Мы собираемся повторно инициализировать репозиторий git, а затем запустить клон подмодуля на этапе сборки нашего развертывания, по сути исправления в поддержку подмодулей в codepipeline/codebuild.

  • Сгенерируйте новый SSH-ключ для вашей учетной записи GitHub, если вы используете организацию, которую вы можете захотеть создать для пользователя развертывания
  • Сохраните этот ключ ssh в вашем хранилище параметров aws ssm put-parameter --name build_ssh_key --type String --value "$(cat id_rsa)" идеальном случае используйте SecureString вместо String, но руководство, aws ssm put-parameter --name build_ssh_key --type String --value "$(cat id_rsa)" я следовал, просто использовало строку, поэтому я Я не уверен, что для командной строки потребуются дополнительные параметры
  • Зайдите в 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."[email protected]:".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:
    - '**/*'

Ответ 2

Я сам столкнулся с этой проблемой и, благодаря потрясающим предложениям @matt-bucci, мне удалось найти что-то вроде надежного решения.

Мой конкретный вариант использования немного отличается - я использую лямбда-слои для уменьшения избыточности лямбды, но все же мне нужно включить слои в качестве подмодулей в репозитории функций лямбды, чтобы CodeBuild мог создавать и тестировать PR. Я также использую CodePipeline для обеспечения непрерывной доставки - поэтому мне нужна система, которая работает как с CodePipeline, так и с CodeBuild.

  1. Я создал новый ключ SSH для использования "пользователем машины", следуя этим инструкциям. В этом случае я использую пользователя машины, чтобы не нужно было создавать новый ключ ssh для каждого проекта, а также для потенциальной поддержки нескольких частных подмодулей.

  2. Я сохранил закрытый ключ в хранилище параметров AWS как SecureString. На самом деле это ничего не меняет в CodeBuild, так как он достаточно умен, чтобы просто знать, как расшифровать ключ

  3. Я присвоил роли "codebuild" управляемое свойство AWS: AmazonSSMReadOnlyAccess - позволяя CodeBuild получить доступ к закрытому ключу.

  4. Я создал свой файл buildspec.yml, используя несколько команд, предложенных @matt-bucci, а также некоторые новые

# 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: "[email protected]: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 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 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 и извлекает точный коммит, который создается. Примечание. Согласно документации AWS, $CODEBUILD_RESOLVED_SOURCE_VERSION не гарантированно присутствует в сборках CodePipeline. Тем не менее, я не видел этот сбой

  3. Наконец, он на самом деле получает субмодули

Очевидно, что это не лучшее решение этой проблемы. Тем не менее, это лучшее, что я могу придумать, учитывая (ненужные) ограничения CodePipeline. Побочным эффектом этого процесса является то, что этап CodePipeline "Source" совершенно бесполезен, поскольку мы просто перезаписываем архивные исходные файлы - он используется только для прослушивания изменений в хранилище.

Уже более 2 лет запрашивается улучшенная функциональность: https://forums.aws.amazon.com/thread.jspa?threadID=248267

Отредактировано 23 января 2019 г.

Я понял (трудный путь), что мой предыдущий ответ не поддерживал сборки CodePipeline, а только сборки, запускаемые напрямую через CodeBuild. Когда CodeBuild отвечает на GitHub Webhook, он клонирует весь репозиторий GitHub, включая папку .git.

Однако при использовании CodePipeline действие "Источник" клонирует репозиторий, проверяет соответствующую ветвь, а затем создает артефакты для необработанных файлов без папки .git. Это означает, что нам нужно инициализировать репозиторий github, чтобы получить доступ к подмодулям.

Ответ 3

Хотя ответ @MattBucci работает, у него есть предостережение о том, что вы можете извлекать только определенную ветвь, а не конкретную фиксацию, которую использует подмодуль.

Чтобы разобраться с этим случаем, что вероятно при использовании подмодулей, необходимо сделать несколько вещей:

1) Создайте git pre-commit hook со следующим содержимым:

#!/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 hook со следующим контентом:

#!/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 файл .submodule-hash, этот файл должен быть зафиксирован для контроля версий.

3) Перейдите к своему проекту сборки кода AWS

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

Добавьте переменную окружения с именем: GIT_KEY, и значением будет кодировка ssh key base 64. (Без разрывов строк, иначе это не сработает).

Вы можете конвертировать его онлайн или использовать любой инструмент или язык программирования.

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 [email protected]$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 hook.

#!/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

SSH не нужен, если вы используете CodeCommit в качестве хранилища. Используйте помощник по учетным данным AWS CLI и клонируйте его по https.

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

Ответ 5

Прошло так много времени с тех пор, как была обнаружена проблема с подмодулями. Но 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.