Note: Steps were valid as of 2019; Beanstalk and console options may have changed since then.
I faced an issue during my CI-CD process, in this process an artifact is created in develop environment with a default configuration that includes a URL to test the development environment; this artifact is immutable and is promoted to the different environments (Staging, QA, Demo, Prod).
The artifact structure will be something similar to this:
MY_APP/
MY_APP.jar
.ebextensions
certificates_deploy.config
additional_commands.config
nginx/
conf.d/
nginx_ssl.conf
The content of those files will be something similar to this:
certificates_deploy.config
Resources:
AWSEBAutoScalingGroup:
Metadata:
AWS::CloudFormation::Authentication:
S3Auth:
type: "s3"
buckets: ["BUCKET-NAME"]
roleName:
"Fn::GetOptionSetting":
Namespace: "aws:autoscaling:launchconfiguration"
OptionName: "IamInstanceProfile"
DefaultValue: "AWS-ACCESS-ROLE"
files:
"/etc/nginx/certs/bundle.crt" :
mode: "000400"
owner: root
group: root
authentication: "S3Auth"
source: https://s3.amazonaws.com/BUCKET-NAME/<PATH_TO_YOUR_BUNDLE>/bundle.crt
"/etc/nginx/certs/my_domain.key" :
mode: "000400"
owner: root
group: root
authentication: "S3Auth"
source: https://s3.amazonaws.com/BUCKET-NAME/<PATH_TO_YOUR_KEY>/my_domain.key
additional_commands.config
container_commands:
01update_ssl_url:
command: /etc/nginx/update_ssl_url.sh "$ENVIRONMENT_NAME" "$APPLICATION_NAME"
06restart_nginx:
command: "service nginx restart"
files:
"/etc/nginx/update_ssl_url.sh":
content: |
#!/usr/bin/env bash
environment_name=$1
application_name=$2
sed -i "s/server_name*/server_name $application_name-$environment_name.my_domain.com;#/" /etc/nginx/conf.d/nginx_ssl.conf
cat /etc/nginx/conf.d/nginx_ssl.conf
mode: "000755"
owner: root
group: root
nginx_ssl.conf
server {
listen 443 http2 ssl default_server;
access_log /var/log/nginx/access.log main;
server_name my-service-dev.my_domain.com;
ssl_certificate /etc/nginx/certs/bundle.crt;
ssl_certificate_key /etc/nginx/certs/my_domain.key;
client_header_timeout 60;
client_body_timeout 60;
keepalive_timeout 60;
...
...
During the Execution will be pass an option file in JSON format with the Environment variables.
env-dev.json
[
{
"Namespace": "aws:elasticbeanstalk:application:environment",
"OptionName": "APPLICATION_NAME",
"Value": "my-service"
},
{
"Namespace": "aws:elasticbeanstalk:application:environment",
"OptionName": "ENVIRONMENT_NAME",
"Value": "dev"
},
{
"Namespace": "aws:elasticbeanstalk:application:environment",
"OptionName": "SERVER_PORT",
"Value": "9999"
}
]
this file will be readed during the insstance update
aws elasticbeanstalk update-environment --environment-name "my-service-dev" --version-label "1.0.0" --option-settings file://env-dev.json
Now according to AWS Documentation the script update_ssl_url.sh should be executed after the artifact is unpacked in the instance, but this does not happen; the script is executed before the artifact is unpacked and the file nginx_ssl.conf is created in the instance giving you the same URL for every environment.
After some investigation I found that I have to use the elasticbeanstalk hooks that allow you to execute scripts after, during or before the deployment.
To be able to reach our goal the file additional-commands.config will be updated adding new lines and commands.
container_commands:
01Install_jq:
command: "yum install -y jq"
02update_ssl_url:
command: /opt/elasticbeanstalk/hooks/appdeploy/post/update_ssl_url.sh
03restart_nginx:
command: "service nginx restart"
files:
"/opt/elasticbeanstalk/hooks/appdeploy/post/update_ssl_url.sh":
content: |
#!/usr/bin/env bash
application_name=$(sudo bash -c '/opt/elasticbeanstalk/bin/get-config environment |jq -r ".APPLICATION_NAME"')
environment_name=$(sudo bash -c '/opt/elasticbeanstalk/bin/get-config environment |jq -r ".ENVIRONMENT_NAME"')
if test -f "/etc/nginx/conf.d/nginx_ssl.conf"; then
sed -i "s/server_name*/server_name $application_name-$environment_name.my_domain.com;#/" /etc/nginx/conf.d/nginx_ssl.conf
cat /etc/nginx/conf.d/nginx_ssl.conf
fi
mode: "000755"
owner: root
group: root
As you can see, we have installed jq this will be used to read the environment variables that are created using the env-dev.json file.
Also we change the file location to /opt/elasticbeanstalk/hooks/appdeploy/post/ that is the PATH that is readed by AWS during the deployment to execute scripts after the deployment.
Using the get-config environment command we will be able to read the environment variables created with the env-dev.josn file, then, the the URL will be updated in the nginx_ssl.conf file and nginx will be restarted.