Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to run Rails migrations and seeding in Amazon Elastic Beanstalk single container Docker environment

I'm working on deploying a Rails application to Elastic Beanstalk using docker and so far everything has worked out. I'm at the point where the application needs to run migrations and seeding of the database, and I'm having trouble figuring out exactly how I need to proceed. It appears that any commands in the /.ebextensions folder run in the context of the host machine and not the docker container. Is that correct?

I'm fine with running a command to execute migrations inside of the docker container after startup, but how do I ensure that the migrations only run on a single instance? Is there an environment variable or some other way I can tell what machine is the leader from within the docker container?


Update: I posted a question in the Amazon Elastic Beanstalk forums asking how to run "commands from Docker host on the container" on the 6th/Aug/15'. You can follow the conversations there as well as they are useful.

like image 428
King'ori Maina Avatar asked Jul 22 '15 20:07

King'ori Maina


2 Answers

I'm not sure the solution you have proposed is going to work. It appears that the current process for EB Docker deployment runs container commands before the new docker container is running, which means that you can't use docker exec on it. I suspect that your commands will execute against the old container which is not yet taken out of service.

After much trial and error I got this working through using container commands with a shell script.

container_commands:
  01_migrate_db:
    command: ".ebextensions/scripts/migrate_db.sh"
    leader_only: true

And the script:

if [ "${PROCESS}" = "WEB" ]; then

  . /opt/elasticbeanstalk/hooks/common.sh

  EB_SUPPORT_FILES=$(/opt/elasticbeanstalk/bin/get-config container -k support_files_dir)

  EB_CONFIG_DOCKER_ENV_ARGS=()

  while read -r ENV_VAR; do
    EB_CONFIG_DOCKER_ENV_ARGS+=(--env "$ENV_VAR")
  done < <($EB_SUPPORT_FILES/generate_env)

  echo "Running migrations for aws_beanstalk/staging-app"
  docker run --rm "${EB_CONFIG_DOCKER_ENV_ARGS[@]}" aws_beanstalk/staging-app bundle exec rake db:migrate || echo "The Migrations failed to run."
fi
true

I wrap the whole script in a check to ensure that migrations don't run on background workers.

I then build the ENV in exactly the same way that EB does when starting the new container so that the correct environment is in place for the migrations.

Finally I run the command against the new container which has been created but is not yet running - aws_beanstalk/staging-app. It exits at the end of the migration and the --rm removes the container automatically.

like image 189
nmott Avatar answered Nov 15 '22 19:11

nmott


Use .ebextensions/01-environment.config:

container_commands:
  01_write_leader_marker:
    command: touch /tmp/is_leader
    leader_only: true

Now add directory /tmp to volumes in Dockerfile / Dockerrun.aws.json.

Then check set all initialization commands like db migration in sh script that first check if file /tmp/is_leader exists and executes them only in this case.

like image 45
smentek Avatar answered Nov 15 '22 19:11

smentek