⬆️ ⬇️

Ansible and Docker, why and why?

There is a lot of interest among the technical community in Docker and Ansible , I hope that after reading this article, you will also share this interest. You will also gain practical skills in the use of Ansible and Docker in setting up a server and environment for a Rails application.



“Why not just take and use Heroku?”, You ask.

First of all, I can run Docker and Ansible on any machine, with any hosting provider. Secondly, I prefer flexibility, convenience. I can, in the same way, run anything, not just web applications. And finally, because I am an experimenter in the shower, I enjoy the understanding of how it all works together. The fundamental basis of Heroku is a Linux container. The same technology lies at the heart of Docker. In fact, one of Docker’s mottos is “Containerization is new virtualization.”



Why Ansible?



After 4 years of active use of Chef, infrastructure as a code has become really tedious for me. I spent more time behind the code that ran my infrastructure, but not behind the infrastructure itself. Any change, no matter how small, will require a lot of effort for a slight benefit.



With Ansible, on the one hand there is data describing the infrastructure, on the other hand there are restrictions between the interaction of other components. This model is much simpler, it allows you to move much faster, allowing you to focus on what my infrastructure is doing. As in the Unix model, Anisible provides modules with a single responsibility, which can be combined in an infinite number of ways.

')

Ansible has no dependencies except Python and SSH. She does not need to install agents on remote machines, she does not leave any kind of garbage after her work. Moreover, it comes with a standard library of modules for managing everything from the package manager in the cloud to the databases.



Why docker?



Docker positions itself as the most reliable and convenient way to deploy a process on a machine. This can be anything from mysqld to redis, ending with a Rails application. In the same effective way as git snapshots and code distribution, Docker does the same with processes. It guarantees that everything you need to run this process will be provided, regardless of the machine on which it is running.



The basic but understandable mistake is comparing the Docker container with the VM. Here the principle of sole responsibility applies; launching one process per container gives ease of changeability and support. This model has stood the test of time in the Unix philosophy; it provides a solid foundation for action.



Customization



Without leaving my terminal, I can get a customized machine from Ansible on one of the following hosts: AWS, Linode, Rackspace, or DigitalOcean. More specifically, with the help of Ansible, I create a new droplet with 2 GB of memory on DigitalOcean in the Amsterdam 2 region in 1 minute 25 seconds. For another 1 minute and 50 seconds, I can get a tuned system with Docker and some other settings. Now that I have a base system, I can deploy my application. Note that I did not set up any programming language or database. Docker himself took care of this.



Ansible executes all commands on remote machines via SSH. My SSH keys lying in the local ssh-agent will be remotely shared via the Ansible SSH session. When, on a remote machine, the code of my application will be cloned or updated, no data will be required for authorization in git, for authorization a forwarding ssh-agent from the local machine will be used.



Docker and application dependencies



I find it amusing that most developers specify the PL version, modules for Python, Ruby gems, or node.js modules needed for their application, but when it comes to something important, for example, a database server or a queue server, they use what is available at the moment. I think this is one of the reasons for the DevOps movement, developers take responsibility for the environment in which they run the application. Docker makes this task easier and simpler by adding a slice of pragmatism and confidence to existing practices.



My application defines dependencies on processes such as MySQL 5.5 and Redis 2.8 including the .docker_container_dependencies file

 gerhard/mysql:5.5 gerhard/redis:2.8 




Ansible playbook will see this file and tell Docker to take the correct images from the image index and run them as containers. Also, these containers are linked to the container of my application. If you want more details about container linking, check out the Docker 0.6.5 announcement.



My application also comes with a Dockerfile that is specific to the Ruby Docker image. When the image is installed, the steps in the Dockerfile ensure that the correct version of Ruby is installed.



 FROM howareyou/ruby:2.0.0-p353 ADD ./ /terrabox RUN \ . /.profile ;\ rm -fr /terrabox/.git ;\ cd /terrabox ;\ bundle install --local ;\ echo '. /.profile && cd /terrabox && RAILS_ENV=test bundle exec rake db:create db:migrate && bundle exec rspec' > /test-terrabox ;\ echo '. /.profile && cd /terrabox && export RAILS_ENV=production && rake db:create db:migrate && bundle exec unicorn -c config/unicorn.rails.conf.rb' > /run-terrabox ;\ # END RUN ENTRYPOINT ["/bin/bash"] CMD ["/run-terrabox"] EXPOSE 3000 




The first step is to copy all the code of my application into the Docker image and load global environment variables added by the previous images. A Ruby Docker image, for example, adds paths to the PATH to load the correct version of Ruby correctly.



Next, I delete the git history because it is not needed in this context. I install all the gems and then create a / test-terrabox file that runs only for tests. The goal of all this is to have a “canary” version that checks the application and all its dependencies, that all Docker containers are linked correctly and all tests passed successfully, before the actual launch of the application.



The command that is called when a new container is started is defined in step CMD.

Running the / run-terrabox command, defined as part of the build process, immediately after the test launch process.



The last instruction in the Dockerfile forwards port 3000 from inside the Docker container to the host machine from which Docker is running. Which can be used by the server or the load balancer for proxying requests to my container application.



Running a Rails application inside the Docker container



For an average Rails application, with about 100 gems somewhere and a lot of integration tests running from under Rails, all of this takes 8 minutes 16 seconds per 2GB and 2 kernel machines, without any local Docker images. If I already have a Ruby, Mysql and Redis image on this machine, it will take 4 minutes and 45 seconds. Moreover, if I already have a reference image of my application, then it takes 2 minutes 23 seconds. If you look, in perspective, deploying a new Rails application, including dependencies such as MySQL and Redis, takes no more than 2 minutes.



It should also be noted that the deployment of the application includes the launch of all tests that take up the minute of time.

Without exaggeration, Docker becomes a simple means of continuous integration, which reserves only test containers for research if tests do not pass, or a new application container starts with the latest version when tests pass. Suddenly, I can check the new code with my customers in minutes, which is guaranteed to be isolated from other versions of the application at the operating system level. Unlike traditional VMs that load in minutes, the Docker spends seconds. Moreover, once I created the Docker image and made sure that all the tests were passed for a specific version of my application, I can upload the image to a private registry, which in turn can be loaded by other Docker machines and launched as a new container, and all this in seconds.



Conclusion



Ansible let me take a fresh look at the infrastructure management process. Docker gave me confidence and stability when it comes to one of the most important development steps, the delivery phase. In combination, they are unmatched.



Getting a fully customized Rails application from scratch in just 12 minutes is impressive for any standard. Getting the basic Continuous Integration system for free with the ability to preview different versions of an application side by side, without affecting the “working” version running on the same machine, is incredibly powerful. It makes me happy, and having reached the end of the article, I can only hope that you will share my joy with me.

Source: https://habr.com/ru/post/217689/



All Articles