• No results found

Pre-Deployment Tasks

In document devops-2-0-toolkit.pdf (Page 189-192)

The first thing we should do is build the tests container. We already used the following command (please don’t run it).

¹³³https://github.com/vfarcic/ms-lifecycle/blob/master/ansible/service.yml

¹³⁴https://github.com/vfarcic/ms-lifecycle/blob/master/ansible/roles/service/tasks/main.yml

1 docker pull \

Replicating the same command in Ansible is very easy with theShell module¹³⁵.

1 - name: Tests container is pulled 2 shell: docker pull \

3 {{ registry_url }}{{ service_name }}-tests 4 delegate_to: 127.0.0.1

5 ignore_errors: yes 6 tags: [service, tests]

7

8 - name: Tests container is built 9 shell: docker build \

10 -t {{ registry_url }}{{ service_name }}-tests \ 11 -f Dockerfile.test \

We changed the command itself so that parts that might be prone to change are used as variables.

The first one is the registry_url that should contain the IP and the port of the Docker registry. The default value is specified in thegroup_vars/all¹³⁶file. The second one is more interesting. We are not creating this role to work with the service books-ms but as something that can be used with (almost) any service since all of them can follow the same pattern. We can do this sorts of things without sacrificing the freedom since the key instructions are stored in a few files located in the repository of each service. The most important ones are the Dockerfile.test and the Dockerfile that define testing and service containers, Docker Compose configurations that define how should containers be run and, finally, the proxy configuration and template. All those files are separated from the process we’re creating, and people in charge of the project have the full freedom to tailor them to their needs. That showcases a very important aspect I’m trying to promote. It is crucial not only to have the right process in place but also to have the scripts, configurations and the code properly located.

Everything that is common to multiple projects should be centralized (as is the case with Ansible

¹³⁵http://docs.ansible.com/ansible/shell_module.html

¹³⁶https://github.com/vfarcic/ms-lifecycle/blob/master/ansible/group_vars/all

playbooks located in thevfarcic/ms-lifecycle¹³⁷repository). On the other hand, things that might be specific to a project should be stored in the repository that project resides in. Storing everything in one centralized place would introduce quite a lot of waiting time since a project team would need to request a change from the delivery team. The other extreme is just as wrong. If everything is stored in the project repositories, there would be quite a lot of duplication. Each project would need to come up with scripts to set up servers, deploy a service, and so on.

Next we specified a single argument chdir. It will make sure that the command is run from the directory that, in this case, contains the Dockerfile.test file. The chdir value is the variable repo_dir that, unlike registry_url does not have the default value. We’ll specify it at runtime when we run the playbook. Then comes the delegate_to instruction. Since we are committed to disrupting the destination server as little as possible, tasks like this one will be run on the localhost (127.0.0.1).

Finally, we set few tags that can be used to filter which tasks will or will not be run.

The reason behind pulling the tests container before building it is to save the time. The execution of the playbook might change from one server to another and, if such a thing happens, without first pulling the container from the Registry, Docker would build all the layers even though most of them are likely to be the same as before. Take a note that we introduced the ignore_errors instruction.

Without it, the playbook would fail if this is the first build of the container and there is nothing to be pulled.

Please keep in mind that the shell module should be avoided in most cases. The idea behind Ansible is to specify the desired behavior and not the action that should be performed. Once that “desire” is run, Ansible will try to “do the right thing”. If, for example, we specify that some package should be installed, Ansible will check whether such a package already exists and do the installation only if it doesn’t. The shell module that we used, in this case, will always run, no matter the state of the system. In this particular situation, that is OK, because Docker itself will make sure that only changed layers are built. It won’t build the whole container every time. Please keep this in mind when designing your roles.

The rest of the commands we used in the pre-deployment phase are as follows (please don’t run them).

6 docker build -t 10.100.198.200:5000/books-ms . 7

8 docker push 10.100.198.200:5000/books-ms

When translated to the Ansible format, the result is as follows.

¹³⁷https://github.com/vfarcic/ms-lifecycle

1 - name: Pre-deployment tests are run

10 - name: Container is built 11 shell: docker build \

12 -t {{ registry_url }}{{ service_name }} \

13 .

19 - name: Container is pushed 20 shell: docker push \

21 {{ registry_url }}{{ service_name }}

22 delegate_to: 127.0.0.1 23 tags: [service]

There’s not much to be said about those tasks. They all use the shell module and are all running on localhost. We run the tests container that, besides the obvious function of checking the quality of the code, compiles the service. The result of that compilation is used to build the service container that is later on pushed to the Docker registry.

The final result can be seen in theroles/service/tasks/pre-deployment.yml¹³⁸file and we can proceed with the deployment tasks.

In document devops-2-0-toolkit.pdf (Page 189-192)