我们正在使用Gitlab.com作为我们的GIT中央回购。以同样的方式,将应用程序部署到AWS Elastic Beanstalk,使用 git aws.push 进行推送,它在后台执行正常的 git push 到Amazon。我想要一种方法来推动gitlab和 Gitlab 推动Elastic Beanstalk。我知道git别名,使用它我能够使用一个命令执行git push和git aws.push,但是,我想要的只是gitlab和从gitlab到AWS。
我在Gitlab Web Hooks思考,也许有些人已经将它翻译成PHP或某种服务器语言来实现Web Hook?或者从Gitlab部署到AWS Elastic Beanstalk的任何其他解决方案。
git aws.push使用Power Shell中的代码对Elastic Beanstalk进行git推送:
$awsSource = @"
using System;
using System.Globalization;
using System.Text;
using System.Security.Cryptography;
namespace Amazon.DevTools
{
public class AWSUser
{
public string AccessKey
{
get;
set;
}
public string SecretKey
{
get;
set;
}
protected internal void Validate()
{
if (string.IsNullOrEmpty(this.AccessKey))
{
throw new InvalidOperationException("[AccessKey]");
}
if (string.IsNullOrEmpty(this.SecretKey))
{
throw new InvalidOperationException("[SecretKey]");
}
}
}
}
namespace Amazon.DevTools
{
public abstract class AWSDevToolsRequest
{
protected const string METHOD = "GIT";
protected const string SERVICE = "devtools";
DateTime dateTime;
public AWSDevToolsRequest()
: this(DateTime.UtcNow)
{
}
public AWSDevToolsRequest(DateTime dateTime)
{
if (dateTime == null)
{
throw new ArgumentNullException("dateTime");
}
this.dateTime = dateTime.ToUniversalTime();
}
public string DateStamp
{
get
{
return this.dateTime.ToString("yyyyMMdd", CultureInfo.InvariantCulture);
}
}
public string DateTimeStamp
{
get
{
return this.dateTime.ToString("yyyyMMddTHHmmss", CultureInfo.InvariantCulture);
}
}
public abstract string DerivePath();
protected internal abstract string DeriveRequest();
public string Host
{
get;
set;
}
public string Region
{
get;
set;
}
public string Service
{
get
{
return AWSDevToolsRequest.SERVICE;
}
}
protected internal virtual void Validate()
{
if (string.IsNullOrEmpty(this.Host))
{
throw new InvalidOperationException("[Host]");
}
if (string.IsNullOrEmpty(this.Region))
{
throw new InvalidOperationException("[Region]");
}
}
}
}
namespace Amazon.DevTools
{
public class AWSElasticBeanstalkRequest : AWSDevToolsRequest
{
public AWSElasticBeanstalkRequest()
: base()
{
}
public AWSElasticBeanstalkRequest(DateTime dateTime)
: base(dateTime)
{
}
public string Application
{
get;
set;
}
public override string DerivePath()
{
this.Validate();
string path = null;
if (string.IsNullOrEmpty(this.Environment))
{
path = string.Format("/v1/repos/{0}/commitid/{1}"
, this.Encode(this.Application)
, this.Encode(this.CommitId));
}
else
{
path = string.Format("/v1/repos/{0}/commitid/{1}/environment/{2}"
, this.Encode(this.Application)
, this.Encode(this.CommitId)
, this.Encode(this.Environment));
}
return path;
}
protected internal override string DeriveRequest()
{
this.Validate();
string path = this.DerivePath();
string request = string.Format("{0}\n{1}\n\nhost:{2}\n\nhost\n", AWSDevToolsRequest.METHOD, path, this.Host);
return request;
}
public string Environment
{
get;
set;
}
public string CommitId
{
get;
set;
}
protected internal override void Validate()
{
base.Validate();
if (string.IsNullOrEmpty(this.Application))
{
throw new InvalidOperationException("[Application]");
}
if (string.IsNullOrEmpty(this.Host))
{
throw new InvalidOperationException("[Host]");
}
}
protected internal string Encode(string plaintext)
{
StringBuilder sb = new StringBuilder();
foreach (byte b in new UTF8Encoding().GetBytes(plaintext))
{
sb.Append(b.ToString("x2", CultureInfo.InvariantCulture));
}
return sb.ToString();
}
}
}
namespace Amazon.DevTools
{
public class AWSDevToolsAuth
{
const string AWS_ALGORITHM = "HMAC-SHA256";
const string HASH_ALGORITHM = "SHA-256";
const string HMAC_ALGORITHM = "HMACSHA256";
const string SCHEME = "AWS4";
const string TERMINATOR = "aws4_request";
AWSUser user;
AWSDevToolsRequest request;
public AWSDevToolsAuth(AWSUser user, AWSDevToolsRequest request)
{
this.user = user;
this.request = request;
}
static byte[] DeriveKey(AWSUser user, AWSDevToolsRequest request)
{
string secret = string.Format("{0}{1}", AWSDevToolsAuth.SCHEME, user.SecretKey);
byte[] kSecret = Encoding.UTF8.GetBytes(secret);
byte[] kDate = AWSDevToolsAuth.Hash(AWSDevToolsAuth.HMAC_ALGORITHM, kSecret, Encoding.UTF8.GetBytes(request.DateStamp));
byte[] kRegion = AWSDevToolsAuth.Hash(AWSDevToolsAuth.HMAC_ALGORITHM, kDate, Encoding.UTF8.GetBytes(request.Region));
byte[] kService = AWSDevToolsAuth.Hash(AWSDevToolsAuth.HMAC_ALGORITHM, kRegion, Encoding.UTF8.GetBytes(request.Service));
byte[] key = AWSDevToolsAuth.Hash(AWSDevToolsAuth.HMAC_ALGORITHM, kService, Encoding.UTF8.GetBytes(AWSDevToolsAuth.TERMINATOR));
return key;
}
public string DerivePassword()
{
this.user.Validate();
this.request.Validate();
string signature = AWSDevToolsAuth.SignRequest(this.user, this.request);
string password = string.Format("{0}Z{1}", this.request.DateTimeStamp, signature);
return password;
}
public Uri DeriveRemote()
{
this.request.Validate();
string path = this.request.DerivePath();
string password = this.DerivePassword();
string username = this.DeriveUserName();
UriBuilder remote = new UriBuilder()
{
Host = this.request.Host,
Path = path,
Password = password,
Scheme = "https",
UserName = username,
};
return remote.Uri;
}
public string DeriveUserName()
{
this.user.Validate();
return this.user.AccessKey;
}
static byte[] Hash(string algorithm, byte[] message)
{
HashAlgorithm hash = HashAlgorithm.Create(algorithm);
byte[] digest = hash.ComputeHash(message);
return digest;
}
static byte[] Hash(string algorithm, byte[] key, byte[] message)
{
KeyedHashAlgorithm hash = KeyedHashAlgorithm.Create(algorithm);
hash.Key = key;
byte[] digest = hash.ComputeHash(message);
return digest;
}
static string SignRequest(AWSUser user, AWSDevToolsRequest request)
{
string scope = string.Format("{0}/{1}/{2}/{3}", request.DateStamp, request.Region, request.Service, AWSDevToolsAuth.TERMINATOR);
StringBuilder stringToSign = new StringBuilder();
stringToSign.AppendFormat("{0}-{1}\n{2}\n{3}\n", AWSDevToolsAuth.SCHEME, AWSDevToolsAuth.AWS_ALGORITHM, request.DateTimeStamp, scope);
byte[] requestBytes = Encoding.UTF8.GetBytes(request.DeriveRequest());
byte[] requestDigest = AWSDevToolsAuth.Hash(AWSDevToolsAuth.HASH_ALGORITHM, requestBytes);
stringToSign.Append(AWSDevToolsAuth.ToHex(requestDigest));
byte[] key = AWSDevToolsAuth.DeriveKey(user, request);
byte[] digest = AWSDevToolsAuth.Hash(AWSDevToolsAuth.HMAC_ALGORITHM, key, Encoding.UTF8.GetBytes(stringToSign.ToString()));
string signature = AWSDevToolsAuth.ToHex(digest);
return signature;
}
static string ToHex(byte[] data)
{
StringBuilder hex = new StringBuilder();
foreach (byte b in data)
{
hex.Append(b.ToString("x2", CultureInfo.InvariantCulture));
}
return hex.ToString();
}
}
}
"@
Add-Type -Language CSharpVersion3 -TypeDefinition $awsSource
# -*-powershell-*-
#
# Sets the AWS.push configuration values
#
# Will read values from the pipeline input if none are present the values are read from the console input instead.
#
function Edit-AWSElasticBeanstalkRemote
{
$data=@($input)
$used=0
$config = Read-Config $False $True
$awsAccessKey = Lookup-Setting $config "global" "AWSAccessKeyId" ("cred","git")
if (!$awsAccessKey -and (ShouldWrite-Credentials $config $false))
{
$awsAccessKeyInput = ($data[$used++] | Input-Data "AWS Access Key")
}
if ($awsAccessKeyInput)
{
$config = Write-Setting $config "cred" "global" "AWSAccessKeyId" $awsAccessKeyInput
}
$awsSecretKey = Lookup-Setting $config "global" "AWSSecretKey" ("cred","git")
if (!$awsSecretKey -and (ShouldWrite-Credentials $config $false))
{
$awsSecretKeyInput = ($data[$used++] | Input-Data "AWS Secret Key")
}
if ($awsSecretKeyInput)
{
$config = Write-Setting $config "cred" "global" "AWSSecretKey" $awsSecretKeyInput
}
$awsRegion = Lookup-Setting $config "global" "Region" ("eb","git")
if (-not $awsRegion)
{
$awsRegion = "us-east-1"
$config = Write-Setting $config "eb" "global" "Region" $awsRegion
}
$awsRegionInput = ($data[$used++] | Input-Data "AWS Region [default to $($awsRegion)]")
if ($awsRegionInput)
{
$awsRegion = $awsRegionInput
$config = Write-Setting $config "eb" "global" "Region" $awsRegionInput
}
$awsHost = Get-Endpoint $awsRegion
if ($awsHost)
{
$config = Write-Setting $config "eb" "global" "DevToolsEndpoint" $awsHost
}
else
{
$awsHostInput = ($data[$used++] | Input-Data "AWS Host [default to git.elasticbeanstalk.us-east-1.amazonaws.com]")
if ($awsHostInput)
{
$config = Write-Setting $config "eb" "global" "DevToolsEndpoint" $awsHostInput
}
else
{
$config = Write-Setting $config "eb" "global" "DevToolsEndpoint" "git.elasticbeanstalk.us-east-1.amazonaws.com"
}
}
$awsApplication = Lookup-Setting $config "global" "ApplicationName" ("eb","git")
if ($awsApplication)
{
$awsApplicationInput = ($data[$used++] | Input-Data "AWS Elastic Beanstalk Application [default to $($awsApplication)]")
}
else
{
$awsApplicationInput = ($data[$used++] | Input-Data "AWS Elastic Beanstalk Application")
}
if ($awsApplicationInput)
{
$config = Write-Setting $config "eb" "global" "ApplicationName" $awsApplicationInput
}
$awsEnvironment = Lookup-Setting $config "global" "EnvironmentName" ("eb","git")
if ($awsEnvironment)
{
$awsEnvironmentInput = ($data[$used++] | Input-Data "AWS Elastic Beanstalk Environment [default to $($awsEnvironment)]")
}
else
{
$awsEnvironmentInput = ($data[$used++] | Input-Data "AWS Elastic Beanstalk Environment")
}
if ($awsEnvironmentInput)
{
$config = Write-Setting $config "eb" "global" "EnvironmentName" $awsEnvironmentInput
}
Write-Config $config
}
#
# Looks up the endpoint for a region
#
# @params $region
# @return The endpoint
#
function Get-Endpoint
{
Param($region)
switch ($region)
{
"us-east-1" { $endpoint = "git.elasticbeanstalk.us-east-1.amazonaws.com" }
"ap-northeast-1" { $endpoint = "git.elasticbeanstalk.ap-northeast-1.amazonaws.com" }
"ap-southeast-1" { $endpoint = "git.elasticbeanstalk.ap-southeast-1.amazonaws.com" }
"ap-southeast-2" { $endpoint = "git.elasticbeanstalk.ap-southeast-2.amazonaws.com" }
"eu-west-1" { $endpoint = "git.elasticbeanstalk.eu-west-1.amazonaws.com" }
"sa-east-1" { $endpoint = "git.elasticbeanstalk.sa-east-1.amazonaws.com" }
"us-west-1" { $endpoint = "git.elasticbeanstalk.us-west-1.amazonaws.com" }
"us-west-2" { $endpoint = "git.elasticbeanstalk.us-west-2.amazonaws.com" }
}
$endpoint
}
#
# Gets the remote URL used for AWS.push
#
# @param $e environment that is deployed too.
# @param $c commit to deploy
# @return The URL
#
function Get-AWSElasticBeanstalkRemote
{
Param([string] $e,
[string] $c,
[bool] $toPush = $FALSE )
trap [System.Management.Automation.MethodInvocationException]
{
if ($_.Exception -and $_.Exception.InnerException)
{
$awsOption = $_.Exception.InnerException.Message
switch ($awsOption)
{
"[AccessKey]" { $awsOption = "aws.accesskey" }
"[Application]" { $awsOption = "aws.elasticbeanstalk.application" }
"[Host]" { $awsOption = "aws.elasticbeanstalk.host" }
"[Region]" { $awsOption = "aws.region" }
"[SecretKey]" { $awsOption = "aws.secretkey" }
}
Write-Host "Missing configuration setting for: $($awsOption)"
}
else
{
Write-Host "An unknown error occurred while computing your temporary password."
}
Write-Host "`nTry running 'git aws.config' to update your repository configuration."
Exit
}
$config = Read-Config
$awsAccessKey = Lookup-Setting $config "global" "AWSAccessKeyId" ("cred","git")
$awsSecretKey = Lookup-Setting $config "global" "AWSSecretKey" ("cred","git")
$awsRegion = Lookup-Setting $config "global" "Region" ("eb","git")
$awsHost = Lookup-Setting $config "global" "DevToolsEndpoint" ("eb","git")
$awsApplication = Lookup-Setting $config "global" "ApplicationName" ("eb","git")
if ($e)
{
$awsEnvironment = $e
}
else
{
$branchName = &git rev-parse --abbrev-ref HEAD
$defaultEnv = Lookup-Setting $config "branches" $branchName ("eb")
if ($defaultEnv)
{
$awsEnvironment = $defaultEnv
}
else
{
$awsEnvironment = Lookup-Setting $config "global" "EnvironmentName" ("eb","git")
}
}
$gitCommitId = $c
$awsUser = New-Object -TypeName Amazon.DevTools.AWSUser
$awsUser.AccessKey = $awsAccessKey
$awsUser.SecretKey = $awsSecretKey
$awsRequest = New-Object -TypeName Amazon.DevTools.AWSElasticBeanstalkRequest
$awsRequest.Region = $awsRegion
$awsRequest.Host = $awsHost
$awsRequest.Application = $awsApplication
$awsRequest.Environment = $awsEnvironment
$awsRequest.CommitId = $gitCommitId
$awsAuth = New-Object -TypeName Amazon.DevTools.AWSDevToolsAuth $awsUser,$awsRequest
$awsRemote = $awsAuth.DeriveRemote()
if($toPush) {
Write-Host "Pushing to environment: $awsEnvironment"
}
return $awsRemote.ToString()
}
#
# Performs the aws.push
#
# @param $e environment that is deployed too.
# @param $c commit to deploy
#
function Invoke-AWSElasticBeanstalkPush
{
Param([string] $e, [string] $c)
$remote = Get-AWSElasticBeanstalkRemote $e $c $TRUE
$src = $c
$dst = "refs/heads/master"
$commit = $src + ":" + $dst
&git push -f $remote $commit
}
#
# Adds the git aliases for aws.push and aws.config to the git repository.
#
function Initialize-AWSElasticBeanstalkRepository
{
$command = 'Import-Module AWSDevTools; $e, $c = Get-Options $args; Get-AWSElasticBeanstalkRemote $e $c'
&git config alias.aws.elasticbeanstalk.remote "!powershell -noprofile -executionpolicy bypass -command '& { $command }'"
$command = 'Import-Module AWSDevTools; $e, $c = Get-Options $args; Invoke-AWSElasticBeanstalkPush $e $c'
&git config alias.aws.push "!powershell -noprofile -executionpolicy bypass -command '& { $command }'"
$command = 'Import-Module AWSDevTools; Edit-AWSElasticBeanstalkRemote'
&git config alias.aws.config "!powershell -noprofile -executionpolicy bypass -command '& { $command }'"
}
#
# Read in data
#
# Will used pipeline data if present, otherwise reads from the console
#
# @param $message The text to display as a prompt
# @return The data collected
#
function Input-Data
{
Param([string] $message)
Write-Host -NoNewline "$($message): "
if (($input.MoveNext()) -and ($input.Current))
{
Write-Host $input.Current
$input.Current
}
else
{
[Console]::In.ReadLine()
}
}
#
# Gets the values for the aws.push and aws.config command options
#
# @param $arr The command line options passed to the command
# @return The options values
#
function Get-Options
{
Param([string[]] $arr)
$e = $null;
$c = $null;
$optionmappings = @{
'--environment' = 'environment';
'-e' = 'environment';
'--commit' = 'commit';
'-c' = 'commit';
'--help' = 'help';
'-h' = 'help'
}
$options = @{}
for ($i=0; $i -lt $arr.count; $i++)
{
$optname = $arr[$i]
$mappedoption = $optionmappings[$optname]
if (!$mappedoption) {
Write-Host("Unknown Option: {0}" -f $arr[$i])
Write-Help
Exit
}
if ($mappedoption -eq "help") {
Write-Help
Exit
}
$value = $arr[++$i]
if (($value -eq $null) -or $optionmappings[$value]) {
Write-Host("You must provide a value for {0}" -f $optname)
Write-Help
Exit
}
if ($options[$mappedoption]) {
Write-Host("--{0} specified twice" -f $mappedoption)
Exit
}
$options[$mappedoption] = $value
}
$e = $options["environment"]
$c = $options["commit"]
if ($c -eq $null) {
$c = "HEAD"
}
$c = Parse-CommitOption $c
$result = $e, $c
$result
}
答案 0 :(得分:2)
首先在gitlab中设置AWS_ACCESS_KEY_ID
和AWS_SECRET_ACCESS_KEY
:https://gitlab.com/snw/<project_name>/settings/ci_cd
然后将.gitlab-ci.yml
文件添加到您的repo的根目录:
variables:
ARCHIVE_NAME: "archive.zip"
ARCHIVE_LOCATION: "deployments/"
S3_BUCKET_NAME: "my-deployments"
ELASTIC_BEANSTALK_APP_NAME: "myAppName"
AWS_REGION: "us-east-1"
elastic_beanstalk_deploy:
image: python:latest
script:
- apt-get update --assume-yes
- apt-get install zip --assume-yes
- zip -r $ARCHIVE_LOCATION$ARCHIVE_NAME .
- pip install awscli
- aws s3 cp $ARCHIVE_LOCATION$ARCHIVE_NAME s3://$S3_BUCKET_NAME/
- aws elasticbeanstalk create-application-version --application-name $ELASTIC_BEANSTALK_APP_NAME --version-label `date "+%Y%m%d-%H%M%S"` --description "$(git log -1 --pretty=%B)" --source-bundle S3Bucket="$S3_BUCKET_NAME",S3Key="$ARCHIVE_NAME" --region $AWS_REGION
道具: