Skip to content

Instantly share code, notes, and snippets.

@ippeiukai
Last active July 31, 2021 21:00
Show Gist options
  • Save ippeiukai/37e812e49f04ea0f26d84d380d050304 to your computer and use it in GitHub Desktop.
Save ippeiukai/37e812e49f04ea0f26d84d380d050304 to your computer and use it in GitHub Desktop.
Running cron in AWS ElasticBeanstalk web tier.
files:
"/tmp/crontab":
mode: "000777"
owner: 'ec2-user'
group: 'ec2-user'
content: |
30 02 * * * sudo /usr/sbin/execute-in-eb-node-app 'node bin/is-eb-master.js' && sudo /usr/sbin/execute-in-eb-node-app 'npm run daily-maintenance'
encoding: plain
container_commands:
01-copy_eb_bin:
command: 'cp -f ./.ebextensions/bin/eb-is-master.js ./bin/'
02-copy_eb_sbin:
command: 'sudo cp -f ./.ebextensions/sbin/execute-in-eb-node-app.sh /usr/sbin/execute-in-eb-node-app'
commands:
01-load_crontab:
command: 'sudo crontab /tmp/crontab'
02-remove_crontab_file:
command: 'rm /tmp/crontab'
#!/bin/bash
# Execute node command with EB's node.js environment.
# Basically, /etc/init/nodejs.conf defines how node command is executed:
# - environment variables
# - add path to node.js installation
# - execute as nodejs user
# Implementation is taken from https://github.com/kopurando/better-faster-elastic-beanstalk/blob/7e20fe7/cron-node.sh
# Note: requires root access.
eval "$(grep -E '^env [A-Za-z0-9_-]+="[^"]+"$' /etc/init/nodejs.conf | sed 's/env /export /g')"
export __EXECUTE_NODE_COMMAND="$1"
cd /var/app/current
exec su -s /bin/sh -c 'PATH=$PATH:$NODE_HOME/bin eval "$__EXECUTE_NODE_COMMAND" 2>&1' nodejs
#!/usr/bin/env node
"use strict";
const checkWhetherEbMasterInstance = require_checkWhetherEbMasterInstance();
checkWhetherEbMasterInstance().then(isMaster => {
process.exit(isMaster ? 0 : 1);
}).catch(err => {
console.log(err);
console.log(err.stack);
process.exit(1);
});
// https://gist.github.com/ippeiukai/e12b2cd3ae6424d220f2a802443e5548
function require_checkWhetherEbMasterInstance() {
let module = {exports: {}};
(function (module) {
"use strict";
const AWS = require('aws-sdk');
const bluebird = require('bluebird');
/**
* @returns {Promise.<boolean>} - is on 'master' instance or not
*/
module.exports = bluebird.coroutine(function* (opts) {
if (opts == null) {
opts = {
// default to use the credentials for the ec2 instance
credentials: new AWS.EC2MetadataCredentials(),
};
}
let instanceId = yield findCurrentInstanceId(opts);
let beanstalkEnvironmentId = yield findEbEnvironmentId(instanceId, opts);
let instanceIds = yield findEbInstanceIds(beanstalkEnvironmentId, opts);
// first in the list is the master
return instanceId === instanceIds[0]
});
const findCurrentInstanceId = function (opts) {
return requestMatadata('/latest/meta-data/instance-id', opts)
};
const findEbEnvironmentId = function (instanceId, opts) {
let params = {
Filters: [
{
Name: "resource-id",
Values: [
instanceId,
]
}
]
};
return requestEc2Tags(params, opts).then(tags => {
let envIdTag = tags.find(t => t.Key === 'elasticbeanstalk:environment-id');
if (envIdTag == null) {
return Promise.reject(new Error('failed to find the value of "elasticbeanstalk:environment-id" tag.'));
}
return envIdTag.Value
})
};
const findEbInstanceIds = function (environmentId, opts) {
let params = {
EnvironmentId: environmentId
};
return requestEbEnvironmentResources(params, opts)
.then(envResources => envResources.Instances.map(it => it.Id))
};
const promisifyMethod = function (obj, name) {
return bluebird.promisify(obj[name], {context: obj})
};
const requestMatadata = function (path, opts) {
let metadata = new AWS.MetadataService(opts);
return promisifyMethod(metadata, 'request')(path)
};
const requestEc2Tags = function (params, opts) {
let ec2 = new AWS.EC2(opts);
return promisifyMethod(ec2, 'describeTags')(params).then(data => data.Tags);
};
const requestEbEnvironmentResources = function (params, opts) {
let elasticbeanstalk = new AWS.ElasticBeanstalk(opts);
return promisifyMethod(elasticbeanstalk, 'describeEnvironmentResources')(params)
.then(data => data.EnvironmentResources)
};
})(module);
return module.exports
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment