11
votes

I have website, which stored on AWS EC2 servers.

We have 2 servers, one for production environment and another one for development and staging environments.

Development and staging environments located in different folders. For example development env stored in /var/www/development, while staging stored in /var/www/staging.

I'd like to use AWS CodeDeploy to upload files directly from bitbucket. I put AppSpec file, which copy source code to /var/www/html folder and install all dependencies and configurations. But I want my AppSpec file to copy source code to /var/www/development or to /var/www/staging depending on Development group, that was selected.

Is there is any way to do it or, maybe, there are some better approach in my situation?

3
Add a tag for both instances, for ex: production server will have tag env:prod and staging server will have env:stage. In your appspec hooks first get this tag first and then decide where to copy your archive.Ravi
@levchuk-ivan did you ever get this working? I'm in a similar situation at the moment. ThanksflopperJ
@flopperJ, yes, but I don't like the solution. By default application release copy to one folder and after deploy script move source code to the folder according to the deployment group nameLiauchuk Ivan

3 Answers

6
votes

The appspec.yml is a bit inflexible so use the following to deploy code in to different folders on the same instance.

version: 0.0
os: linux
files:
  - source: /
    destination: /var/www/my-temp-dir
permissions:
  - object: /var/www/my-temp-dir
    owner: ec2-user
    group: ec2-user
hooks:
  BeforeInstall:
    - location: ci/integrations-deploy-pre.sh
      runas: root
  AfterInstall:
    - location: ci/integrations-deploy-post.sh
      runas: root

Inside of my integrations-deploy-post.sh file, I then use the CodeDeploy environment variables to move the files in to the place I need them to be;

#!/bin/bash
    
if [ "$DEPLOYMENT_GROUP_NAME" == "Staging" ]
then
    cp -R /var/www/my-temp-dir /var/www/my-staging-dir
    chown -R ec2-user:ec2-user /var/www/my-staging-dir

    # Insert other commands that need to run...
fi

if [ "$DEPLOYMENT_GROUP_NAME" == "UAT" ]
then
    cp -R /var/www/my-temp-dir /var/www/my-uat-dir
    chown -R ec2-user:ec2-user /var/www/my-uat-dir

    # Insert other commands that need to run...
fi

NOTE: In my integrations-deploy-post.sh You'll also need the commands you want to run on production. Removed for simplicity.

4
votes

The recommended way to change AppSpec or custom scripts behavior is to utilize environment variables provided by the CodeDeploy agent. You have access to the deployment group name and the application name.

if [ "$DEPLOYMENT_GROUP_NAME" == "Staging" ]; then
  # Copy to /var/www/staging
elif [ "$DEPLOYMENT_GROUP_NAME" == "Development" ]; then
  # Copy to /var/www/development
elif [ "$DEPLOYMENT_GROUP_NAME" == "Production" ]; then
  # Copy to /var/www/html
else
  # Fail the deployment
fi
0
votes

I had the same problem, but I used source control as a solution to this. My workflow is using Gitlab CI > AWS Code Pipeline (S3 Source and CodeDeploy).

So in my development branch, my AppSpec file would look like this:-

version: 0.0
os: linux
files:
  - source: /
    destination: /var/www/html/my-project-dev
hooks:
  AfterInstall:
    - location: scripts/after_install.sh
      timeout: 400
      runas: root

in my staging branch:-

version: 0.0
os: linux
files:
  - source: /
    destination: /var/www/html/my-project-staging
hooks:
  AfterInstall:
    - location: scripts/after_install.sh
      timeout: 400
      runas: root

My Gitlab-CI just uses a shell executor to my EC2 instance and it basically compresses my project folder and uploads to S3.

.gitlab-ci.yml

stages:
  - deploy
setup dependencies:
  stage: .pre
  script:
    - echo "Setup Dependencies"
    - pip install awscli
deploy to s3:
  stage: deploy
  script:
    - tar -cvzf /tmp/artifact_$CI_COMMIT_REF_NAME.tar ./*
    - echo "Copy artifact to S3"
    - aws s3 cp /tmp/artifact_$CI_COMMIT_REF_NAME.tar s3://project-artifacts/

clean up:
  stage: .post
  script:
    - echo "Removing generated artifact"
    - rm /tmp/artifact_$CI_COMMIT_REF_NAME.tar

Note that $CI_COMMIT_REF_NAME is used to differentiate the artifact file being generated. In development branch it would be artifact_development.tar, in staging branch artifact_staging.tar.

Then, I have 2 pipelines listening to the two respective artifacts which deploys to 2 different CodeDeploy Application.

Not sure if this is the best way, surely welcome any suggestions that is better