Run one off commands via SSH in Elastic Beanstalk and Django - django

I'm trying to solve this problem for a while now and can't seem to solve it. There are various scenarios in which I would want to be able to run a custom command on Elastic beanstalk. I want to use this command after the server started (.ebextensions does not work here). E. g.
python manage.py send_pending_emails_via_cronjob
The problem here is that I'm not able to run any commands without the environment variables set. My app needs e. g. DJANGO_SECRET_KEY, RDS_DB_NAME... Out of the box, these variables are only available when the server starts up. They are not available when I enter the EC2 instance via eb ssh - they are also not present in the virtual python environment on the instance.
I tried: finding the file that contains the variables at /opt/elasticbeanstalk/env to source it. But read access to the file is restricted to the root user (I haven't yet figured out how to access the server as root) - however, this feels very complicated and like an unintuitive thing to do. I suspect there to be a more elegant solution.
Did someone solve this already?

Related

setting up Strapi on AWS - the docs don't seem to show everything

I am trying to setup Strapi on AWS and am have been following the Strapi documentation here. But when I get to starting the EC2 instance, I have run into a few errors that were not addressed in in the docs. App keys, jwt secrets, and other env config variables. Has anyone else tried this and run into similar issues? And how did you get around things? I have been running pm2 log in my EC2 instance to get the errors.
I would post my config and everything but I have followed the strapi docs to the letter, and have run through every single step a dozen times now, and I don't want to basically copy and paste the docs in here again. My last step is to get Strapi to run on the EC2 instance, but I keep running into errors like this
error: Missing jwtSecret. Please, set configuration variable "jwtSecret" for the users-permissions plugin in config/plugins.js (ex: you can generate one using Node with `crypto.randomBytes(16).toString('base64')`).
which don't seem to be addressed in the docs anywhere.
This is because you need to expose the JWT_SECRET (and ADMIN_JWT_SECRET) environment variable. You can do it by adding (you can add a line like this: JWT_SECRET=A_RANDOM_STRING_HERE) it to the .env file located at the root of your Strapi project.
You can find more details here: https://docs.strapi.io/developer-docs/latest/plugins/users-permissions.html#jwt-configuration
You can generate jwt
node -e "console.log(require('crypto').randomBytes(256).toString('base64'));"

How to edit Elastic Beanstalk code without re-uploading application?

I am building a web-app using Elastic beanstalk on AWS and was wondering if there was a way that I can edit the source code without having to re-upload a zip of my application every time I want to make an edit.
Thanks!
The Elastic Beanstalk environment is based on EC2 instances. You can connect to your instances using SSH and, inside the instance, download your source code. If you use a non compiled language, like Javascript (Node) or Python you can edit the code directly. If you use Java you will need to upload the source code and compile it. Maybe using the environment JDK.
But keep in mind two details:
You must install your compiled/edited code in the same path used by elastic beanstalk;
If your instance is reinitialized, your changes will be lost, because in this case eb will get a fresh copy of your code based on your last upload.

How Docker and Ansible fit together to implement Continuous Delivery/Continuous Deployment

I'm new to the configuration management and deployment tools. I have to implement a Continuous Delivery/Continuous Deployment tool for one of the most interesting projects I've ever put my hands on.
First of all, individually, I'm comfortable with AWS, I know what Ansible is, the logic behind it and its purpose. I do not have same level of understanding of Docker but I got the idea. I went through a lot of Internet resources, but I can't get the the big picture.
What I've been struggling is how they fit together. Using Ansible, I can manage my Infrastructure as Code; building EC2 instances, installing packages... I can even deploy a full application by pulling its code, modify config files and start web server. Docker is, itself, a tool that packages an application and ensures that it can be run wherever you deploy it.
My problems are:
How does Docker (or Ansible and Docker) extend the Continuous Integration process!?
Suppose we have a source code repository, the team members finish working on a feature and they push their work. Jenkins detects this, runs all the acceptance/unit/integration test suites and if they all passed, it declares it as a stable build. How Docker fits here? I mean when the team pushes their work, does Jenkins have to pull the Docker file source coded within the app, build the image of the application, start the container and run all the tests against it or it runs the tests the classic way and if all is good then it builds the Docker image from the Docker file and saves it in a private place?
Should Jenkins tag the final image using x.y.z for example!?
Docker containers configuration :
Suppose we have an image built by Jenkins stored somewhere, how to handle deploying the same image into different environments, and even, different configurations parameters ( Vhosts config, DB hosts, Queues URLs, S3 endpoints, etc...) What is the most flexible way to deal with this issue without breaking Docker principles? Are these configurations backed in the image when it gets build or when the container based on it is started, if so how are they injected?
Ansible and Docker:
Ansible provides a Docker module to manage Docker containers. Assuming I solved the problems mentioned above, when I want to deploy a new version x.t.z of my app, I tell Ansible to pull that image from where it was stored on, start the app container, so how to inject the configuration settings!? Does Ansible have to log in the Docker image, before it's running ( this sounds insane to me ) and use its Jinja2 templates the same way with a classic host!? If not, how is this handled?!
Excuse me if it was a long question or if I misspelled something, but this is my thinking out loud. I'm blocked for the past two weeks and I can't figure out the correct workflow. I want this to be a reference for future readers.
Please, it would very helpful to read your experiences and solutions because this looks like a common workflow.
I would like to answer in parts
How does Docker (or Ansible and Docker) extend the Continuous Integration process!?
Since docker images same everywhere, you use your docker images as if they are production images. Therefore, when somebody committed a code, you build your docker image. You run tests against it. When all tests pass, you tag that image accordingly. Since docker is fast, this is a feasible workflow.
Also docker changes are incremental; therefore, your images will have minimal impact on storage. Also when your tests fail, you may also choose to save that image too. In this way, developer will pull that image and investigate easily why your tests failed. Developer may choose to run tests in their machine too since docker images in jenkins and their machine are not different.
What this brings that all developers will have same environment, same version of all software since you decide which one will be used in docker images. I have come across to bugs that are due to differences between developer machines. For example in the same operating system, unicode settings may affect your code. But in docker images all developers will test against same settings, same version software.
Docker containers configuration :
If you are using a private repository, and you should use one, then configuration changes will not affect hard disk space much. Therefore except security configurations, such as db passwords, you can apply configuration changes to docker images(Baking the Configuration into the Container). Then you can use ansible to apply not-stored configurations to deployed images before/after startup using environment variables or Docker Volumes.
https://dantehranian.wordpress.com/2015/03/25/how-should-i-get-application-configuration-into-my-docker-containers/
Does Ansible have to log in the Docker image, before it's running (
this sounds insane to me ) and use its Jinja2 templates the same way
with a classic host!? If not, how is this handled?!
No, ansible will not log in the Docker image, but ansible with Jinja2 templates can be used to change dockerfile. You can change dockerfile with templates and can inject your configuration to different files. Tag your files accordingly and you have configured images to spin up.
Regarding your question about handling multiple environment configurations using the same Docker image, I have been planning on using a Service Discovery tool like Consul as a centralized config/property management tool. So, when you start your container up, you set an ENV var that tells it what application it is (appID), and what environment config it should use (ex: MyApplication:Dev) and it will pull its config from Consul at startup. I still have to investigate the security around Consul (as if we are storing DB connection credentials in there for example, how do we restrict who can query/update those values). I don't want to just use this for containers, but all apps in general. Another cool capability is to change the config value in Consul and have a hook back into your app to apply the changes immediately (maybe like a REST endpoint on your app to push changes down to and dynamically apply it). Of course your app has to be written to support this!
You might be interested in checking out Martin Fowler's blog articles on immutable infrastructure and on Phoenix servers.
Although not a complete solution, I have suggestions for two of your issues. Although they might not be perfect, these are the practices we are using in our workflow, and prove themselves so far.
Defining different environments - supposing you've written a different Ansible role for each environment you launch, we define an environment variable setting the environment we wish the container to belong to. We then download the suitable configuration file from an S3 bucket using the env variable set before into the container (which should be possible if you supply AWS creds or give your server an IAM role) and inject these parameters into the code when building it.
Ansible doesn't need to log into the docker app, but the solution is a bit tricky. I've tried two ways of tackling this problem, and both aren't ideal. The first one is to download the configuration file as part of the docker image command line, and build the app on container startup. While this solution works - it breaches the Docker philosophy and makes the image highly prone to build errors.
Another solution is pushing several images to your docker hub repo, and then pulling the appropriate image according to the environment at hand.
In a broader stroke, I've tried launching our app completely with Ansible and it was hell, many configuration steps are tricky and get trickier when you try to implement them as a playbook. When I switched to maintaining the severs alone with Ansible, and deploying the app itself with Docker things got a lot easier.

Jenkins/Hudson call script on AWS EC2 Instance

Today, on my work, when we need to deploy a Play! Framework (1.2.7) app in our EC2 Instance (AWS), we need to access the server and call a script that download all the source code, precompile the source code, start Play! Framework and restart nginx (everything in one script - .sh).
This process work fine today, but in emergency cases it's very slowly because we need to access de EC2 Instance (with key pair) and depending on the location the internet is slowly.
I want to know if is possible to use Hudson/Jenkins to just call this script on my EC2 Instances. I know that Hudson/Jenkins have a lot of functionality (test, build, etc.) but for now I just want to deploy my app (call the script from ec2-instance).
If anyone knows another tool that help, I will be very grateful.
Thanks.
You can use/build SBT plugins to run the remote command, or simply exec the local ssh with the command, but that can get quite hard to debug.
If you can build your instance to bootstrap itself from scratch, for example with a UserData script, then all you need to do is terminate your old instance and start a new one, and that is much easier to automate.

How do I know what .ebextensions config file to create?

I think I'm on the right path. I can use .ebextensions to change some of the conf files for the instance I'm running. Since I'm using Elastic Beanstalk, and that a lot of the software is shrinkwrapped (which I'm fine with), I should be using .ebextensions as a means of modifying the environment.
I want to employ some form of mod_rewrite config, but I know nothing of this Amazon Linux. I don't even know what the web server is. I've been through the console for the past few hours and see no trace of the things I want to override.
Apparently I can setup a shell to take a look around, but modifying things that way will cause things to be overridden since Beanstalk is handling config. I'm not entirely sure on that last point.
Should I just ssh and play in userland like a typical unix host?
You can definitely ssh to the instance, and see around. But remember, that your changes are not persistent. You should look at .ebextensions config files as the way to re-run your commands on the host, plus more.
It might take some time to see where ElasticBeanstalk stores configuration files and all other interesting things.
To get you started, your app files are located at: /opt/python/current/app and if you are using Python, it is located in virtual environment at: /opt/python/run/venv/bin/python27
Customizing the Software on EC2 Instances Running Linux guide contains detailed information on what you can do:
Packages - install packages
Sources - retrieve archives
Files - operations with files
Users - anything with users
Groups - anything with groups
Commands - execute instance commands
Container_commands - execute commands after the container is
extracted
Services - launch services
Option_settings - configure
container settings
See if that satisfies your requirements, if not, come back to StackOverflow and ask more questions.