├── README.md ├── Vagrantfile ├── artefacts ├── config │ └── config_multi-nodes.yaml ├── playbooks │ ├── install_docker.yaml │ ├── install_gitlab.yaml │ ├── install_java.yaml │ ├── install_jenkins.yaml │ ├── nfs_clients.yaml │ └── nfs_server.yaml ├── scripts │ ├── config_ansible.sh │ ├── install_ansible.sh │ └── ssh_pass.sh └── templates │ └── exports.j2 ├── images ├── Ansible Provisioning.pptx ├── image-01-01.png ├── image-01-02.png ├── image-01-03.png ├── image-01-04.png ├── image-01-05.png └── image-01-06.png └── install.sh /README.md: -------------------------------------------------------------------------------- 1 | # End-to-end automated environment with Vagrant, Ansible, Docker, Jenkins, and GitLab. 2 | 3 | Ansible is a beautifully simple agentless (and serverless) **Configuration Management** (CM) tool for configuration management, provisioning, and deployment. Its strength is the agentless nature that makes it simple and powerful. Configuration Management refers to the process of systematically handling changes to a system in a way that it maintains integrity over time, also known as idempotent. Like most of the Idempotent Infrastructure tools (no matter how many times you call the operation, the result will be the same, unless a change needs to be made.), it provides the ability through declarative language to describe system configuration; Ansible uses YAML (YAML Ain't Markup Language) is a human-readable data serialization language syntax for expressing **Ansible Playbooks**. Ansible Playbooks are the building blocks for all the use cases of Ansible. The different YAML tags are classified into four types knows as declaration, vars, tasks, and handlers; through this article, we will take a practical approach in describing each one. 4 | 5 | ## Getting Started 6 | This step-by-step demo gives you a walkthrough on how to build a CI **(Continuous Integration)** environment with minimal effort; all the steps come together to you in the form of a use case solving a specific issue with a development environment. Apart from installing Vagrant and VirtualBox everything else is automated using Ansible Playbooks; we will go over six playbooks, each one solves a specific problem in the automation. The code is provided for you to put the demo to the test; each section builds from the previous one; it's best that we follow the documentation systematically. Thus, I have that expectation that you will leverage the **Git** repository and follow along; so that a build goes well from start to end. 7 | 8 | Many of the Ansible notions from Inventory, Playbooks, Modules, Variables, Conditionals, and Loops are covered. I have intentionally not used Roles; this is probably going to be used on a future article, as this can be somewhat complicated and overwhelming trying to pack too many concepts on the first article. 9 | 10 | This real-life scenario will address: 11 | - **Provisioning servers with Vagrant and VirtualBox.** 12 | - **Provisioning applications with Ansible Playbooks and Host Inventory file.** 13 | - **Continuous Integration with GitLab, Jenkins, and Docker.** 14 | 15 | ## Prerequisites 16 | To follow along you are required to have these programs in place: 17 | - [Vagrant](https://www.vagrantup.com/downloads.html): download the proper package for your operating system and architecture. 18 | - [VirtualBox](https://www.virtualbox.org/wiki/Downloads): by downloading, you agree to the terms and conditions of the respective license. 19 | 20 | This article will use **ubuntu/trusty64** image with version **20180404.0.0**; feel free to choose your own Box by visiting [Vagrantbox.es](http://www.vagrantbox.es/) 21 | 22 | ## Provisioning Servers with Vagrant and VirtualBox 23 | 24 | We are starting with a customized configuration file for this walkthrough. The end-to-end provisioning time is in the order of 75-90 minutes depending on our your available resource, most of the time is spent provisioning GitLab, not sure why but half of it is consumed installing the server. 25 | 26 | The configuration file can be found at ./artefacts/config/config_multi-nodes.yaml 27 | 28 | ![Server Provisioning with Vagrant and VirtualBox](./images/image-01-01.png) 29 | **FIGURE 1: Server Provisioning with Vagrant and VirtualBox.** 30 | 31 | 32 | ### Vagrant configuration file 33 | File location: ./artefacts/config/config_multi-nodes.yaml 34 | 35 | ``` yaml 36 | vagrant_box: ubuntu/trusty64 37 | vagrant_box_version: "20180404.0.0" 38 | vagrant_ip: 192.168.99. 39 | vagrant_hostname: vagrant 40 | vagrant_memory: 4096 41 | vagrant_directory: /vagrant 42 | vagrant_cpu: 2 43 | vagrant_box_check_update: false 44 | vagrant_domain_name: sample.com 45 | 46 | ``` 47 | 48 | 49 | ## Building the servers with Vagrantfile 50 | 51 | The heavy lifting happens in the Vagrantfile section, with six images to build and shared directory. 52 | - NFS Server 53 | - NFS Client 54 | - Docker 55 | - Jenkins 56 | - GitLab 57 | - Ansible 58 | 59 | File location: ./Vagrantfile 60 | 61 | ``` ruby 62 | # -*- mode: ruby -*- 63 | # vi: set ft=ruby : 64 | # Use config.yaml for basic VM configuration. 65 | 66 | require 'yaml' 67 | dir = File.dirname(File.expand_path(__FILE__)) 68 | config_nodes = "#{dir}/artefacts/config/config_multi-nodes.yaml" 69 | 70 | if !File.exist?("#{config_nodes}") 71 | raise 'Configuration file is missing! Please make sure that the configuration exists and try again.' 72 | end 73 | vconfig = YAML::load_file("#{config_nodes}") 74 | 75 | BRIDGE_NET = vconfig['vagrant_ip'] 76 | DOMAIN = vconfig['vagrant_domain_name'] 77 | RAM = vconfig['vagrant_memory'] 78 | 79 | servers=[ 80 | { 81 | :hostname => "nfsserver." + "#{DOMAIN}", 82 | :ip => "#{BRIDGE_NET}" + "150", 83 | :ram => 1024 84 | }, 85 | { 86 | :hostname => "nfsclient." + "#{DOMAIN}", 87 | :ip => "#{BRIDGE_NET}" + "151", 88 | :ram => 1024 89 | }, 90 | { 91 | :hostname => "docker." + "#{DOMAIN}", 92 | :ip => "#{BRIDGE_NET}" + "152", 93 | :ram => 2048 94 | }, 95 | { 96 | :hostname => "jenkins." + "#{DOMAIN}", 97 | :ip => "#{BRIDGE_NET}" + "153", 98 | :ram => "#{RAM}" 99 | }, 100 | { 101 | :hostname => "gitlab." + "#{DOMAIN}", 102 | :ip => "#{BRIDGE_NET}" + "154", 103 | :ram => "#{RAM}" 104 | }, 105 | { 106 | :hostname => "ansible." + "#{DOMAIN}", 107 | :ip => "#{BRIDGE_NET}" + "155", 108 | :ram => "#{RAM}", 109 | :install_ansible => "./artefacts/scripts/install_ansible.sh", 110 | :config_ansible => "./artefacts/scripts/config_ansible.sh", 111 | :source => "./artefacts/.", 112 | :destination => "/home/vagrant/" 113 | } 114 | ] 115 | 116 | Vagrant.configure(2) do |config| 117 | config.vm.synced_folder ".", vconfig['vagrant_directory'], :mount_options => ["dmode=777", "fmode=666"] 118 | servers.each do |machine| 119 | config.vm.define machine[:hostname] do |node| 120 | node.vm.box = vconfig['vagrant_box'] 121 | node.vm.box_version = vconfig['vagrant_box_version'] 122 | node.vm.hostname = machine[:hostname] 123 | node.vm.network "private_network", ip: machine[:ip] 124 | node.vm.provider "virtualbox" do |vb| 125 | vb.customize ["modifyvm", :id, "--natdnshostresolver1", "on"] 126 | vb.cpus = vconfig['vagrant_cpu'] 127 | vb.memory = machine[:ram] 128 | vb.name = machine[:hostname] 129 | if (!machine[:install_ansible].nil?) 130 | if File.exist?(machine[:install_ansible]) 131 | node.vm.provision :shell, path: machine[:install_ansible] 132 | end 133 | if File.exist?(machine[:config_ansible]) 134 | node.vm.provision :file, source: machine[:source] , destination: machine[:destination] 135 | node.vm.provision :shell, privileged: false, path: machine[:config_ansible] 136 | end 137 | end 138 | end 139 | end 140 | end 141 | end 142 | 143 | ``` 144 | ## Install Ansible repository 145 | The ./artefacts/scripts/install_ansible.sh contains all the required instructions to: 146 | - Install Ansible repository 147 | - Install Ansible 148 | - Install expect, dos2unix & tree 149 | - Adjust timezone to be Singapore 150 | - Add vagrant user to sudoers 151 | - Generating SSH key password configuration on ansible server to later access remote servers 152 | 153 | 154 | ``` sh 155 | #!/bin/sh 156 | 157 | # Install Ansible repository. 158 | apt -y update && apt-get -y upgrade 159 | apt-get install software-properties-common 160 | apt-add-repository ppa:ansible/ansible -y 161 | 162 | # Install Ansible. 163 | apt-get update 164 | apt-get install ansible -y 165 | 166 | # Install expect, dos2unix & tree 167 | apt-get install expect -y 168 | apt-get install dos2unix -y 169 | apt-get install tree -y 170 | 171 | # Cleanup unneded packages 172 | apt-get -y autoremove 173 | 174 | # Adjust timezone to be Singapore 175 | ln -sf /usr/share/zoneinfo/Asia/Singapore /etc/localtime 176 | 177 | # Add vagrant user to sudoers. 178 | echo "vagrant ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers 179 | sed -i "s/^.*requiretty/#Defaults requiretty/" /etc/sudoers 180 | 181 | # Disable daily apt unattended updates. 182 | #echo 'APT::Periodic::Enable "0";' >> /etc/apt/apt.conf.d/10periodic 183 | 184 | # generating password configuration on ansible server to later access remote servers 185 | echo vagrant | sudo -S su - vagrant -c "ssh-keygen -t rsa -f /home/vagrant/.ssh/id_rsa -q -P ''" 186 | ``` 187 | 188 | 189 | ## Provision applications with Ansible Playbooks and Host Inventory file 190 | 191 | The playbook is the core component of any Ansible configuration. Each Ansible playbook contains one or multiple plays, which defines the work to be done for a configuration on a managed server. Ansible plays are written in YAML, as mentioned in the introduction section. In addition to Playbooks, Ansible uses an **INI** file as inventory source, the INI file based inventory, sections are groups or group related with special : modifiers. An administrator creates each play with environment-specific parameters for the target machines; in our case, we have a total of six that will build, the **NFS server, NFS client, Docker, Java, Jenkins, and GitLab**. 192 | 193 | ![Application Provisioning with Ansible](./images/image-01-02.png) 194 | **FIGURE 2: Application Provisioning with Ansible.** 195 | 196 | This code uses Expect; expect is a program that automates interactions with applications that expose a text terminal interface. It should be noted that using passwords as command-line arguments, like in this example, is a huge security hole; you could use Vault or other programs to encrypt the password, we aim to make the demo simple and easy to use. Our disclaimer, this is not production ready grade. 197 | 198 | File location: ./artefacts/scripts/ssh_pass.sh 199 | 200 | ``` sh 201 | #!/usr/bin/expect -f 202 | 203 | set host_user [lindex $argv 0] 204 | set host_pass [lindex $argv 1] 205 | set host_name [lindex $argv 2] 206 | 207 | # no need for timeout 1 208 | set timeout 60 209 | 210 | spawn /usr/bin/ssh-copy-id -i /home/vagrant/.ssh/id_rsa.pub $host_user@$host_name 211 | expect { 212 | "*yes/no*" { send "yes\r" ; exp_continue } 213 | "*assword:" { send "$host_pass\r" ; exp_continue } 214 | timeout { exit } 215 | } 216 | 217 | ``` 218 | - Adding addresses to the /etc/hosts file 219 | - Generating an SSH key 220 | - Adding the server IPs to the hosts file 221 | - Configuration of the INI file under /etc/ansible/hosts 222 | - Transferring public key 223 | 224 | Creating six PlayBooks; each playbook is self explanatory: 225 | - ansible-playbook ~/artefacts/playbooks/nfs_server.yaml 226 | - ansible-playbook ~/artefacts/playbooks/nfs_clients.yaml 227 | - ansible-playbook ~/artefacts/playbooks/install_java.yaml 228 | - ansible-playbook ~/artefacts/playbooks/install_jenkins.yaml 229 | - ansible-playbook ~/artefacts/playbooks/install_docker.yaml 230 | - ansible-playbook ~/artefacts/playbooks/install_gitlab.yaml 231 | 232 | File location: ./artefacts/scripts/config_ansible.sh 233 | ``` bash 234 | #!/bin/sh 235 | 236 | USER=vagrant 237 | PASSWORD=vagrant 238 | 239 | # add addresses to /etc/hosts 240 | echo "192.168.99.155 ansible.sample.com" | sudo tee -a /etc/hosts 241 | echo "192.168.99.154 gitlab.sample.com" | sudo tee -a /etc/hosts 242 | echo "192.168.99.153 jenkins.sample.com" | sudo tee -a /etc/hosts 243 | echo "192.168.99.152 docker.sample.com" | sudo tee -a /etc/hosts 244 | echo "192.168.99.151 nfsclient.sample.com" | sudo tee -a /etc/hosts 245 | echo "192.168.99.150 nfsserver.sample.com" | sudo tee -a /etc/hosts 246 | 247 | echo " " | sudo tee -a /etc/ansible/hosts 248 | echo "[all]" | sudo tee -a /etc/ansible/hosts 249 | echo "gitlab.sample.com" | sudo tee -a /etc/ansible/hosts 250 | echo "jenkins.sample.com" | sudo tee -a /etc/ansible/hosts 251 | echo "docker.sample.com" | sudo tee -a /etc/ansible/hosts 252 | echo "nfsclient.sample.com" | sudo tee -a /etc/ansible/hosts 253 | echo "nfsserver.sample.com" | sudo tee -a /etc/ansible/hosts 254 | 255 | echo " " | sudo tee -a /etc/ansible/hosts 256 | echo "[test]" | sudo tee -a /etc/ansible/hosts 257 | echo "nfsserver.sample.com" | sudo tee -a /etc/ansible/hosts 258 | echo "nfsclient.sample.com" | sudo tee -a /etc/ansible/hosts 259 | 260 | echo " " | sudo tee -a /etc/ansible/hosts 261 | echo "[nfs-server]" | sudo tee -a /etc/ansible/hosts 262 | echo "nfsserver.sample.com" | sudo tee -a /etc/ansible/hosts 263 | 264 | echo " " | sudo tee -a /etc/ansible/hosts 265 | echo "[nfs-client]" | sudo tee -a /etc/ansible/hosts 266 | echo "nfsclient.sample.com" | sudo tee -a /etc/ansible/hosts 267 | 268 | echo " " | sudo tee -a /etc/ansible/hosts 269 | echo "[jenkins]" | sudo tee -a /etc/ansible/hosts 270 | echo "jenkins.sample.com" | sudo tee -a /etc/ansible/hosts 271 | 272 | echo " " | sudo tee -a /etc/ansible/hosts 273 | echo "[docker]" | sudo tee -a /etc/ansible/hosts 274 | echo "docker.sample.com" | sudo tee -a /etc/ansible/hosts 275 | 276 | echo " " | sudo tee -a /etc/ansible/hosts 277 | echo "[gitlab]" | sudo tee -a /etc/ansible/hosts 278 | echo "gitlab.sample.com" | sudo tee -a /etc/ansible/hosts 279 | 280 | #cat /etc/ansible/hosts 281 | dos2unix ~/artefacts/scripts/ssh_pass.sh 282 | chmod +x ~/artefacts/scripts/ssh_pass.sh 283 | #chown vagrant:vagrant ssh_pass.sh 284 | 285 | # password less authentication using expect scripting language 286 | ~/artefacts/scripts/ssh_pass.sh $USER $PASSWORD "ansible.sample.com" 287 | ~/artefacts/scripts/ssh_pass.sh $USER $PASSWORD "nfsclient.sample.com" 288 | ~/artefacts/scripts/ssh_pass.sh $USER $PASSWORD "nfsserver.sample.com" 289 | ~/artefacts/scripts/ssh_pass.sh $USER $PASSWORD "docker.sample.com" 290 | ~/artefacts/scripts/ssh_pass.sh $USER $PASSWORD "jenkins.sample.com" 291 | ~/artefacts/scripts/ssh_pass.sh $USER $PASSWORD "gitlab.sample.com" 292 | 293 | ansible-playbook ~/artefacts/playbooks/nfs_server.yaml 294 | ansible-playbook ~/artefacts/playbooks/nfs_clients.yaml 295 | ansible-playbook ~/artefacts/playbooks/install_java.yaml 296 | ansible-playbook ~/artefacts/playbooks/install_jenkins.yaml 297 | ansible-playbook ~/artefacts/playbooks/install_docker.yaml 298 | ansible-playbook ~/artefacts/playbooks/install_gitlab.yaml 299 | ``` 300 | 301 | #### Instructions: 302 | - Installing NFS Server 303 | - Create mountable dir 304 | - Make sure the mount drive has a filesystem 305 | - Set mountpoints 306 | - Ensure NFS utilities are installed 307 | - Copy /etc/exports 308 | - Restart NFS server 309 | 310 | File location: ./artefacts/playbooks/nfs_server.yaml 311 | 312 | ``` yaml 313 | --- 314 | - name: Installing NFS Server 315 | hosts: nfs-server 316 | become: true 317 | 318 | vars: 319 | mountable_share_drive: '/dev/sda1' 320 | nfsexport: /share 321 | 322 | tasks: 323 | - name: Create mountable dir 324 | file: path={{ nfsexport }} state=directory mode=777 owner=root group=root 325 | tags: nfs-server 326 | 327 | - name: make sure the mount drive has a filesystem 328 | filesystem: fstype=ext4 dev={{ mountable_share_drive | default('/dev/sda1') }} 329 | tags: nfs-server 330 | 331 | - name: set mountpoints 332 | mount: name={{ nfsexport }} src={{ mountable_share_drive | default('/dev/sda1') }} fstype=auto opts=defaults,nobootwait dump=0 passno=2 state=mounted 333 | tags: nfs-server 334 | 335 | - name: Ensure NFS utilities are installed. 336 | apt: 337 | name: ['nfs-common','nfs-kernel-server'] 338 | state: present 339 | update_cache: yes 340 | tags: nfs-server 341 | 342 | - name: copy /etc/exports 343 | template: src=~/artifacts/templates/exports.j2 dest=/etc/exports owner=root group=root 344 | tags: nfs-server 345 | 346 | - name: restart nfs server 347 | service: name=nfs-kernel-server state=restarted 348 | tags: nfs-server 349 | ``` 350 | Jinja2 format 351 | File location: ./artefacts/templates/exports.j2 352 | Ansible uses Jinja2 templating to enable dynamic expressions and access to variables as shown below: 353 | ``` jinja2 354 | # /etc/exports: the access control list for filesystems which may be exported 355 | # to NFS clients. See exports(5). 356 | # 357 | # Example for NFSv2 and NFSv3: 358 | # /srv/homes hostname1(rw,sync,no_subtree_check) hostname2(ro,sync,no_subtree_check) 359 | # 360 | # Example for NFSv4: 361 | # /srv/nfs4 gss/krb5i(rw,sync,fsid=0,crossmnt,no_subtree_check) 362 | # /srv/nfs4/homes gss/krb5i(rw,sync,no_subtree_check) 363 | # 364 | {{ nfsexport }} {{ hostvars[inventory_hostname]['facter_ipaddress_eth1'] }}/24(rw,sync,no_root_squash,no_subtree_check) 365 | 366 | ``` 367 | 368 | #### Instructions: 369 | - Installing NFS Client 370 | - Ensure NFS common is installed 371 | - Create mountable dir 372 | - Set mountpoints 373 | 374 | File location: ./artefacts/playbooks/nfs_clients.yaml 375 | 376 | ``` yaml 377 | --- 378 | - name: Installing NFS Client 379 | hosts: nfs-clients 380 | become: true 381 | 382 | vars: 383 | nfsserver: 192.168.99.150 384 | nfs_mountpoint: /nfs 385 | nfsexport: /share 386 | 387 | tasks: 388 | - name: Ensure NFS common is installed. 389 | apt: name=nfs-common state=present update_cache=yes 390 | 391 | - name: Create mountable dir 392 | file: path={{ nfs_mountpoint }} state=directory mode=777 owner=root group=root 393 | 394 | - name: set mountpoints 395 | mount: name={{ nfs_mountpoint }} src={{ nfsserver }}:{{ nfsexport }} fstype=nfs opts=defaults,nobootwait dump=0 passno=2 state=mounted 396 | ``` 397 | 398 | #### Instructions: 399 | - Install Oracle Java version 8 400 | - Install dependencies 401 | - Install add-apt-repostory 402 | - Add Oracle Java Repository 403 | - Add an apt key by id from a keyserver 404 | - Accept Java 8 License 405 | - Update cache and ignore errors in case of problems 406 | - Purge java 8 installer - to avoid problems if installation is repeated 407 | - Install Oracle Java 8 408 | 409 | File location: ./artefacts/playbooks/install_java.yaml 410 | 411 | ``` yaml 412 | --- 413 | - name: Install Oracle Java version 8 414 | hosts: jenkins 415 | become: true 416 | 417 | tasks: 418 | - name: Install dependencies 419 | become: yes 420 | apt: 421 | name: "{{ packages }}" 422 | vars: 423 | packages: 424 | - software-properties-common 425 | - dirmngr 426 | state: latest 427 | 428 | - name: Install add-apt-repostory 429 | become: yes 430 | apt: name=software-properties-common state=latest 431 | 432 | - name: Add Oracle Java Repository 433 | become: yes 434 | apt_repository: 435 | repo: deb http://ppa.launchpad.net/webupd8team/java/ubuntu trusty main 436 | state: present 437 | 438 | - name: Add an apt key by id from a keyserver 439 | become: yes 440 | apt_key: 441 | keyserver: keyserver.ubuntu.com 442 | id: EEA14886 443 | 444 | - name: Accept Java 8 License 445 | become: yes 446 | debconf: name='oracle-java8-installer' question='shared/accepted-oracle-license-v1-1' value='true' vtype='select' 447 | 448 | - name: update cache and ignore errors in case of problems 449 | become: yes 450 | apt: update_cache=yes 451 | ignore_errors: yes 452 | 453 | - name: purge java 8 installer - to avoid problems if installation is repeated 454 | become: yes 455 | apt: 456 | name: oracle-java8-installer 457 | purge: yes 458 | state: absent 459 | 460 | - name: Install Oracle Java 8 461 | become: yes 462 | apt: 463 | name: "{{ packages }}" 464 | vars: 465 | packages: 466 | - ca-certificates 467 | - oracle-java8-installer 468 | - oracle-java8-set-default 469 | state: latest 470 | ``` 471 | 472 | #### Instructions: 473 | - Install Jenkins 474 | - Ensure the jenkins apt repository key is installed 475 | - Ensure the repository is configured 476 | - Install Jenkins package 477 | - Start & Enable Jenkins 478 | - Sleep for 30 seconds and continue with play 479 | - Get init password Jenkins 480 | - Print init password Jenkins 481 | 482 | File location: ./artefacts/playbooks/install_jenkins.yaml 483 | 484 | ``` yaml 485 | --- 486 | - name: Install Jenkins 487 | hosts: jenkins 488 | gather_facts: false 489 | become: true 490 | 491 | tasks: 492 | - name: Ensure the jenkins apt repository key is installed 493 | apt_key: 494 | url: https://pkg.jenkins.io/debian-stable/jenkins.io.key 495 | state: present 496 | 497 | - name: Ensure the repository is configured 498 | apt_repository: 499 | repo: deb https://pkg.jenkins.io/debian-stable binary/ 500 | state: present 501 | 502 | - name: Install Jenkins 503 | apt: 504 | name: jenkins 505 | state: present 506 | 507 | - name: Start & Enable Jenkins 508 | service: 509 | name: jenkins 510 | state: started 511 | 512 | - name: Sleep for 30 seconds and continue with play 513 | wait_for: 514 | timeout: 30 515 | 516 | - name: Get init password Jenkins 517 | shell: cat /var/lib/jenkins/secrets/initialAdminPassword 518 | changed_when: false 519 | register: result 520 | 521 | - name: Print init password Jenkins 522 | debug: 523 | var: result.stdout 524 | ``` 525 | 526 | #### Instructions: 527 | - Install Docker 528 | - Ensure old versions of Docker are not installed. 529 | - Install list of packages 530 | - APT - Add Docker GPG key 531 | - Add Docker APT repository 532 | - Install Docker CE 533 | - Add vagrant to docker goup 534 | - Restart Docker 535 | 536 | File location: ./artefacts/playbooks/install_docker.yaml 537 | 538 | ``` yaml 539 | --- 540 | - name: Install Docker 541 | hosts: docker 542 | become: true 543 | 544 | vars: 545 | ansible_distribution_release: trusty 546 | theuser: vagrant 547 | 548 | tasks: 549 | - name: Ensure old versions of Docker are not installed. 550 | package: 551 | name: 552 | - docker 553 | - docker-engine 554 | state: absent 555 | 556 | - name: Install list of packages 557 | package: 558 | name: 559 | - apt-transport-https 560 | - ca-certificates 561 | - software-properties-common 562 | state: latest 563 | update_cache: yes 564 | 565 | - name: APT - Add Docker GPG key 566 | apt_key: 567 | keyserver: keyserver.ubuntu.com 568 | id: 9DC858229FC7DD38854AE2D88D81803C0EBFCD88 569 | 570 | - name: Add Docker APT repository 571 | apt_repository: 572 | repo: deb [arch=amd64] https://download.docker.com/linux/ubuntu {{ ansible_distribution_release }} stable 573 | 574 | - name: Install Docker CE 575 | apt: 576 | name: docker-ce 577 | state: present 578 | update_cache: yes 579 | 580 | - name: add docker goup 581 | user: 582 | name: {{ theuser }} 583 | append: yes 584 | groups: docker 585 | 586 | handlers: 587 | - name: Restart Docker 588 | systemd: 589 | name: docker 590 | state: restarted 591 | ``` 592 | 593 | #### Instructions: 594 | - Install GitLab 595 | - Checking to make sure postfix is installed 596 | - Install GitLab repository 597 | - Run GitLab repository script 598 | - Install GitLab CE 599 | - Run ufw allow http script 600 | - Run ufw allow https script 601 | - Run ufw allow OpenSSH script 602 | - Restart with reconfigure 603 | - GitLab Restart with restart 604 | - GitLab gitlab-runsvdir status 605 | 606 | File location: ./artefacts/playbooks/install_gitlab.yaml 607 | 608 | ``` yaml 609 | --- 610 | - name: Install GitLab 611 | hosts: gitlab 612 | become: true 613 | 614 | tasks: 615 | - name: Checking to make sure postfix is installed 616 | apt: 617 | name: 618 | - postfix 619 | - mailutils 620 | - ca-certificates 621 | - curl 622 | - openssh-server 623 | state: present 624 | tags: [postfix] 625 | when: ansible_os_family == 'Debian' 626 | 627 | - name: Install GitLab repository 628 | get_url: 629 | url: https://packages.gitlab.com/install/repositories/gitlab/gitlab-ce/script.deb.sh 630 | dest: /tmp/script.deb.sh 631 | mode: 0777 632 | 633 | - name: Run GitLab repository script 634 | shell: /tmp/script.deb.sh 635 | 636 | - name: Install GitLab CE 637 | package: 638 | name: 639 | - gitlab-ce 640 | state: latest 641 | update_cache: yes 642 | 643 | - name: Run ufw allow http script 644 | command: ufw allow http 645 | 646 | - name: Run ufw allow https script 647 | command: ufw allow https 648 | 649 | - name: Run ufw allow OpenSSH script 650 | command: ufw allow OpenSSH 651 | 652 | - name: Restart with reconfigure 653 | command: gitlab-ctl reconfigure 654 | 655 | - name: GitLab Restart with restart 656 | command: gitlab-ctl restart 657 | 658 | - name: GitLab gitlab-runsvdir status 659 | command: service gitlab-runsvdir status 660 | ``` 661 | 662 | ## Continuous Integration with GitLab, Jenkins and Docker 663 | A well implemented DevOps (development & operations) process should mean delivering better code at a faster pace. We aimed to adopt a set of practices that automates the processes between software development and IT teams — using the available tool, such as Vagrant and VirtualBox for server provisioning and application adopting the likes of Ansible and finally embracing the development life cycle while delivering features with GitLab, Jenkins, and Docker for frequent release by fostering Continuous Integration. 664 | - Developers check the code locally on their computers 665 | - When completed — they commit changes to the repository 666 | - Repository sends a request (webhook) to CI system 667 | - CI server runs a job (tests, coverage, check syntax and others) 668 | - CI server releases saved artifacts for testing 669 | - If the build or tests fail, the CI server alerts the team 670 | - The team fixes the issue with constant deploy and feedback mechanism in place. 671 | 672 | 673 | ![Continuous Integration with GitLab, Jenkins and Docker](./images/image-01-03.png) 674 | **FIGURE 3: Continuous Integration with GitLab, Jenkins and Docker** 675 | 676 | ![GitLab configured for code check-in](./images/image-01-05.png) 677 | **FIGURE 4: GitLab configured for code** 678 | 679 | ![Jenkins Installed software](./images/image-01-04.png) 680 | **FIGURE 5: Jenkins Installed software** 681 | 682 | ![Current Docker version ](./images/image-01-06.png) 683 | 684 | **FIGURE 6: Current Docker version** 685 | 686 | ## Putting it all together 687 | 688 | Issue the command below to start the automated process; depending on your server the provisioning time is in the order of 75-90 minutes for this demo to work as planned, the specifications required are 16 GB RAM and 250 GB of HDD. 689 | 690 | ```sh 691 | git clone https://github.com/ernesen/infra-ansible.git 692 | cd infra-ansible 693 | vagrant up --provider=virtualbox 694 | ``` 695 | 696 | ``` log 697 | Bringing machine 'nfsserver.sample.com' up with 'virtualbox' provider... 698 | Bringing machine 'nfsclient.sample.com' up with 'virtualbox' provider... 699 | Bringing machine 'docker.sample.com' up with 'virtualbox' provider... 700 | Bringing machine 'jenkins.sample.com' up with 'virtualbox' provider... 701 | Bringing machine 'gitlab.sample.com' up with 'virtualbox' provider... 702 | Bringing machine 'ansible.sample.com' up with 'virtualbox' provider... 703 | ==> nfsserver.sample.com: Importing base box 'ubuntu/trusty64'... 704 | 705 | [KProgress: 90% 706 | [K==> nfsserver.sample.com: Matching MAC address for NAT networking... 707 | ==> nfsserver.sample.com: Checking if box 'ubuntu/trusty64' version '20180404.0.0' is up to date... 708 | ==> nfsserver.sample.com: Setting the name of the VM: nfsserver.sample.com 709 | ==> nfsserver.sample.com: Clearing any previously set forwarded ports... 710 | ==> nfsserver.sample.com: Vagrant has detected a configuration issue which exposes a 711 | ==> nfsserver.sample.com: vulnerability with the installed version of VirtualBox. The 712 | ==> nfsserver.sample.com: current guest is configured to use an E1000 NIC type for a 713 | ==> nfsserver.sample.com: network adapter which is vulnerable in this version of VirtualBox. 714 | ==> nfsserver.sample.com: Ensure the guest is trusted to use this configuration or update 715 | ==> nfsserver.sample.com: the NIC type using one of the methods below: 716 | ==> nfsserver.sample.com: 717 | ==> nfsserver.sample.com: https://www.vagrantup.com/docs/virtualbox/configuration.html#default-nic-type 718 | ==> nfsserver.sample.com: https://www.vagrantup.com/docs/virtualbox/networking.html#virtualbox-nic-type 719 | ==> nfsserver.sample.com: Clearing any previously set network interfaces... 720 | ==> nfsserver.sample.com: Preparing network interfaces based on configuration... 721 | nfsserver.sample.com: Adapter 1: nat 722 | nfsserver.sample.com: Adapter 2: hostonly 723 | ==> nfsserver.sample.com: Forwarding ports... 724 | nfsserver.sample.com: 22 (guest) => 2222 (host) (adapter 1) 725 | ==> nfsserver.sample.com: Running 'pre-boot' VM customizations... 726 | ==> nfsserver.sample.com: Booting VM... 727 | ==> nfsserver.sample.com: Waiting for machine to boot. This may take a few minutes... 728 | nfsserver.sample.com: SSH address: 127.0.0.1:2222 729 | nfsserver.sample.com: SSH username: vagrant 730 | nfsserver.sample.com: SSH auth method: private key 731 | nfsserver.sample.com: Warning: Remote connection disconnect. Retrying... 732 | nfsserver.sample.com: Warning: Connection reset. Retrying... 733 | nfsserver.sample.com: 734 | nfsserver.sample.com: Vagrant insecure key detected. Vagrant will automatically replace 735 | nfsserver.sample.com: this with a newly generated keypair for better security. 736 | nfsserver.sample.com: 737 | nfsserver.sample.com: Inserting generated public key within guest... 738 | ==> nfsserver.sample.com: Machine booted and ready! 739 | ==> nfsserver.sample.com: Checking for guest additions in VM... 740 | nfsserver.sample.com: The guest additions on this VM do not match the installed version of 741 | nfsserver.sample.com: VirtualBox! In most cases this is fine, but in rare cases it can 742 | nfsserver.sample.com: prevent things such as shared folders from working properly. If you see 743 | nfsserver.sample.com: shared folder errors, please make sure the guest additions within the 744 | nfsserver.sample.com: virtual machine match the version of VirtualBox you have installed on 745 | nfsserver.sample.com: your host and reload your VM. 746 | nfsserver.sample.com: 747 | nfsserver.sample.com: Guest Additions Version: 4.3.36 748 | nfsserver.sample.com: VirtualBox Version: 5.2 749 | ==> nfsserver.sample.com: [vagrant-hostsupdater] Checking for host entries 750 | ==> nfsserver.sample.com: [vagrant-hostsupdater] Writing the following entries to (C:/windows/system32/drivers/etc/hosts) 751 | ==> nfsserver.sample.com: [vagrant-hostsupdater] 192.168.99.150 nfsserver.sample.com # VAGRANT: 89d7264420c8560cccab02598b0f211b (nfsserver.sample.com) / 26e57c02-65a7-4633-aa73-4c27c76dccbe 752 | ==> nfsserver.sample.com: [vagrant-hostsupdater] This operation requires administrative access. You may skip it by manually adding equivalent entries to the hosts file. 753 | ==> nfsserver.sample.com: Setting hostname... 754 | ==> nfsserver.sample.com: Configuring and enabling network interfaces... 755 | ``` 756 | ## Conclusion 757 | What got my attention was the fact that Ansible uses **SSH**, with no agents to install on remote systems. There are many possible ways to approach this. In my attempt to learn Ansible as a Configuration Management and automation tool for Infrastructure as Code **(IaC)**; along the way, I was able to showcase how to stand up new environments and apps in minutes. The time spent exploring the different facets of the tool and understanding its strengths and weakness in automating end-to-end environment were valuable to my learning. This article intended to show that building a **sandbox** is no longer a tedious task and anyone can and should try spinning one up as needed. 758 | 759 | #### References: 760 | * [System administration and monitoring of Linux / Windows servers and video CDN](http://sysadm.pp.ua/linux/sistemy-virtualizacii/vagrantfile.html) 761 | * [Gitlab installation with Ansible and Docker](https://www.djouxtech.net/posts/gitlab-installation-with-ansible-and-docker/) 762 | * [Ansible template for automated GitLab server setup in Docker container](https://itsyndicate.org/blog/install-and-configure-gitlab-server-inside-docker/) 763 | * [How To Install and Configure GitLab on Ubuntu 18.04 ](https://www.digitalocean.com/community/tutorials/how-to-install-and-configure-gitlab-on-ubuntu-18-04) 764 | * [How To Install Gitlab On Ubuntu 16.04](https://www.youtube.com/watch?v=0-y38nF2q08) 765 | * [How to Install and Configure GitLab on Ubuntu 18.04 LTS](https://www.howtoforge.com/tutorial/how-to-install-and-configure-gitlab-on-ubuntu-1804/) 766 | * [How to Install and Configure GitLab CE on Ubuntu 18.04 / 16.04 Sever](https://www.linuxtechi.com/install-configure-gitlab-ce-ubuntu-18-04-16-04/) 767 | * [Installing docker and docker-compose on remote server with Ansible](http://www.inanzzz.com/index.php/post/lvwk/installing-docker-and-docker-compose-on-remote-server-with-ansible) 768 | * [Docker Tutorial 1: Docker Installation in Ubuntu 18.04](https://medium.com/@sh.tsang/installation-of-docker-3b18d9e70bea) 769 | * [Add docker gpg key using ansible](https://www.reddit.com/r/devops/comments/9pmd4n/add_docker_gpg_key_using_ansible/) 770 | * [Install Oracle Java 8 / 9 in Ubuntu 16.04, Linux Mint 18](http://tipsonubuntu.com/2016/07/31/install-oracle-java-8-9-ubuntu-16-04-linux-mint-18/) 771 | * [Ansible – install Oracle Java 8 on Debian / Ubuntu](http://clouds.freeideas.cz/subdom/clouds/2017/09/11/ansible-install-oracle-java-8-on-debian-ubuntu/) 772 | * [Installing docker and docker-compose on remote server with Ansible](http://www.inanzzz.com/index.php/post/lvwk/installing-docker-and-docker-compose-on-remote-server-with-ansible) 773 | * [A minimal Docker Ansible role](https://ops.tips/blog/docker-ansible-role/) 774 | -------------------------------------------------------------------------------- /Vagrantfile: -------------------------------------------------------------------------------- 1 | # -*- mode: ruby -*- 2 | # vi: set ft=ruby : 3 | # Use config.yaml for basic VM configuration. 4 | 5 | require 'yaml' 6 | dir = File.dirname(File.expand_path(__FILE__)) 7 | config_nodes = "#{dir}/artefacts/config/config_multi-nodes.yaml" 8 | 9 | if !File.exist?("#{config_nodes}") 10 | raise 'Configuration file is missing! Please make sure that the configuration exists and try again.' 11 | end 12 | vconfig = YAML::load_file("#{config_nodes}") 13 | 14 | BRIDGE_NET = vconfig['vagrant_ip'] 15 | DOMAIN = vconfig['vagrant_domain_name'] 16 | RAM = vconfig['vagrant_memory'] 17 | 18 | servers=[ 19 | { 20 | :hostname => "nfsserver." + "#{DOMAIN}", 21 | :ip => "#{BRIDGE_NET}" + "150", 22 | :ram => 1024 23 | }, 24 | { 25 | :hostname => "nfsclient." + "#{DOMAIN}", 26 | :ip => "#{BRIDGE_NET}" + "151", 27 | :ram => 1024 28 | }, 29 | { 30 | :hostname => "docker." + "#{DOMAIN}", 31 | :ip => "#{BRIDGE_NET}" + "152", 32 | :ram => 2048 33 | }, 34 | { 35 | :hostname => "jenkins." + "#{DOMAIN}", 36 | :ip => "#{BRIDGE_NET}" + "153", 37 | :ram => "#{RAM}" 38 | }, 39 | { 40 | :hostname => "gitlab." + "#{DOMAIN}", 41 | :ip => "#{BRIDGE_NET}" + "154", 42 | :ram => "#{RAM}" 43 | }, 44 | { 45 | :hostname => "ansible." + "#{DOMAIN}", 46 | :ip => "#{BRIDGE_NET}" + "155", 47 | :ram => "#{RAM}", 48 | :install_ansible => "./artefacts/scripts/install_ansible.sh", 49 | :config_ansible => "./artefacts/scripts/config_ansible.sh", 50 | :source => "./artefacts/.", 51 | :destination => "/home/vagrant/" 52 | } 53 | ] 54 | 55 | Vagrant.configure(2) do |config| 56 | config.vm.synced_folder ".", vconfig['vagrant_directory'], :mount_options => ["dmode=777", "fmode=666"] 57 | servers.each do |machine| 58 | config.vm.define machine[:hostname] do |node| 59 | node.vm.box = vconfig['vagrant_box'] 60 | node.vm.box_version = vconfig['vagrant_box_version'] 61 | node.vm.hostname = machine[:hostname] 62 | node.vm.network "private_network", ip: machine[:ip] 63 | node.vm.provider "virtualbox" do |vb| 64 | vb.customize ["modifyvm", :id, "--natdnshostresolver1", "on"] 65 | vb.cpus = vconfig['vagrant_cpu'] 66 | vb.memory = machine[:ram] 67 | vb.name = machine[:hostname] 68 | if (!machine[:install_ansible].nil?) 69 | if File.exist?(machine[:install_ansible]) 70 | node.vm.provision :shell, path: machine[:install_ansible] 71 | end 72 | if File.exist?(machine[:config_ansible]) 73 | node.vm.provision :file, source: machine[:source] , destination: machine[:destination] 74 | node.vm.provision :shell, privileged: false, path: machine[:config_ansible] 75 | end 76 | end 77 | end 78 | end 79 | end 80 | end 81 | -------------------------------------------------------------------------------- /artefacts/config/config_multi-nodes.yaml: -------------------------------------------------------------------------------- 1 | vagrant_box: ubuntu/trusty64 2 | vagrant_box_version: "20180404.0.0" 3 | vagrant_ip: 192.168.99. 4 | vagrant_hostname: vagrant 5 | vagrant_memory: 4096 6 | vagrant_directory: /vagrant 7 | vagrant_cpu: 2 8 | vagrant_box_check_update: false 9 | vagrant_domain_name: sample.com 10 | -------------------------------------------------------------------------------- /artefacts/playbooks/install_docker.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Install Docker 3 | hosts: docker 4 | become: true 5 | 6 | vars: 7 | ansible_distribution_release: trusty 8 | theuser: vagrant 9 | 10 | tasks: 11 | - name: Ensure old versions of Docker are not installed. 12 | package: 13 | name: 14 | - docker 15 | - docker-engine 16 | state: absent 17 | 18 | - name: Install list of packages 19 | package: 20 | name: 21 | - apt-transport-https 22 | - ca-certificates 23 | - software-properties-common 24 | state: latest 25 | update_cache: yes 26 | 27 | - name: APT - Add Docker GPG key 28 | apt_key: 29 | keyserver: keyserver.ubuntu.com 30 | id: 9DC858229FC7DD38854AE2D88D81803C0EBFCD88 31 | 32 | - name: Add Docker APT repository 33 | apt_repository: 34 | repo: deb [arch=amd64] https://download.docker.com/linux/ubuntu {{ ansible_distribution_release }} stable 35 | 36 | - name: Install Docker CE 37 | apt: 38 | name: docker-ce 39 | state: present 40 | update_cache: yes 41 | 42 | - name: add docker goup 43 | user: 44 | name: "{{ theuser }}" 45 | append: yes 46 | groups: docker 47 | 48 | handlers: 49 | - name: Restart Docker 50 | systemd: 51 | name: docker 52 | state: restarted 53 | 54 | -------------------------------------------------------------------------------- /artefacts/playbooks/install_gitlab.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Install GitLab 3 | hosts: gitlab 4 | become: true 5 | 6 | tasks: 7 | - name: Checking to make sure postfix is installed 8 | apt: 9 | name: 10 | - postfix 11 | - mailutils 12 | - ca-certificates 13 | - curl 14 | - openssh-server 15 | state: present 16 | tags: [postfix] 17 | when: ansible_os_family == 'Debian' 18 | 19 | - name: Install GitLab repository 20 | get_url: 21 | url: https://packages.gitlab.com/install/repositories/gitlab/gitlab-ce/script.deb.sh 22 | dest: /tmp/script.deb.sh 23 | mode: 0777 24 | 25 | - name: Run GitLab repository script 26 | shell: /tmp/script.deb.sh 27 | 28 | - name: Install GitLab CE 29 | package: 30 | name: 31 | - gitlab-ce 32 | state: latest 33 | update_cache: yes 34 | 35 | - name: Run ufw allow http script 36 | command: ufw allow http 37 | 38 | - name: Run ufw allow https script 39 | command: ufw allow https 40 | 41 | - name: Run ufw allow OpenSSH script 42 | command: ufw allow OpenSSH 43 | 44 | - name: Restart with reconfigure 45 | command: gitlab-ctl reconfigure 46 | 47 | - name: GitLab Restart with restart 48 | command: gitlab-ctl restart 49 | 50 | - name: GitLab gitlab-runsvdir status 51 | command: service gitlab-runsvdir status -------------------------------------------------------------------------------- /artefacts/playbooks/install_java.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Install Oracle Java version 8 3 | hosts: jenkins 4 | become: true 5 | 6 | tasks: 7 | - name: Install dependencies 8 | become: yes 9 | apt: 10 | name: "{{ packages }}" 11 | vars: 12 | packages: 13 | - software-properties-common 14 | - dirmngr 15 | state: latest 16 | 17 | - name: Install add-apt-repostory 18 | become: yes 19 | apt: name=software-properties-common state=latest 20 | 21 | - name: Add Oracle Java Repository 22 | become: yes 23 | apt_repository: 24 | repo: deb http://ppa.launchpad.net/webupd8team/java/ubuntu trusty main 25 | state: present 26 | 27 | - name: Add an apt key by id from a keyserver 28 | become: yes 29 | apt_key: 30 | keyserver: keyserver.ubuntu.com 31 | id: EEA14886 32 | 33 | - name: Accept Java 8 License 34 | become: yes 35 | debconf: name='oracle-java8-installer' question='shared/accepted-oracle-license-v1-1' value='true' vtype='select' 36 | 37 | - name: update cache and ignore errors in case of problems 38 | become: yes 39 | apt: update_cache=yes 40 | ignore_errors: yes 41 | 42 | - name: purge java 8 installer - to avoid problems if installation is repeated 43 | become: yes 44 | apt: 45 | name: oracle-java8-installer 46 | purge: yes 47 | state: absent 48 | 49 | - name: Install Oracle Java 8 50 | become: yes 51 | apt: 52 | name: "{{ packages }}" 53 | vars: 54 | packages: 55 | - ca-certificates 56 | - oracle-java8-installer 57 | - oracle-java8-set-default 58 | state: latest 59 | 60 | -------------------------------------------------------------------------------- /artefacts/playbooks/install_jenkins.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Install Jenkins 3 | hosts: jenkins 4 | gather_facts: false 5 | become: true 6 | 7 | tasks: 8 | - name: Ensure the jenkins apt repository key is installed 9 | apt_key: 10 | url: https://pkg.jenkins.io/debian-stable/jenkins.io.key 11 | state: present 12 | 13 | - name: Ensure the repository is configured 14 | apt_repository: 15 | repo: deb https://pkg.jenkins.io/debian-stable binary/ 16 | state: present 17 | 18 | - name: Install Jenkins 19 | apt: 20 | name: jenkins 21 | state: present 22 | 23 | - name: Start & Enable Jenkins 24 | service: 25 | name: jenkins 26 | state: started 27 | 28 | - name: Sleep for 30 seconds and continue with play 29 | wait_for: 30 | timeout: 30 31 | 32 | - name: Get init password Jenkins 33 | shell: cat /var/lib/jenkins/secrets/initialAdminPassword 34 | changed_when: false 35 | register: result 36 | 37 | - name: Print init password Jenkins 38 | debug: 39 | var: result.stdout 40 | -------------------------------------------------------------------------------- /artefacts/playbooks/nfs_clients.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Installing NFS Client 3 | hosts: nfs-clients 4 | become: true 5 | 6 | vars: 7 | nfsserver: 192.168.99.150 8 | nfs_mountpoint: /nfs 9 | nfsexport: /share 10 | 11 | tasks: 12 | - name: Ensure NFS common is installed. 13 | apt: name=nfs-common state=present update_cache=yes 14 | 15 | - name: Create mountable dir 16 | file: path={{ nfs_mountpoint }} state=directory mode=777 owner=root group=root 17 | 18 | - name: set mountpoints 19 | mount: name={{ nfs_mountpoint }} src={{ nfsserver }}:{{ nfsexport }} fstype=nfs opts=defaults,nobootwait dump=0 passno=2 state=mounted 20 | 21 | -------------------------------------------------------------------------------- /artefacts/playbooks/nfs_server.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Installing NFS Server 3 | hosts: nfs-server 4 | become: true 5 | 6 | vars: 7 | mountable_share_drive: '/dev/sda1' 8 | nfsexport: /share 9 | src_exports: ~/artefacts/templates/exports.j2 10 | #nfsserver: hostvars[inventory_hostname]['facter_ipaddress_eth1'] #192.168.99.150 11 | 12 | tasks: 13 | - name: Create mountable dir 14 | file: path={{ nfsexport }} state=directory mode=777 owner=root group=root 15 | tags: nfs_server 16 | 17 | - name: make sure the mount drive has a filesystem 18 | filesystem: fstype=ext4 dev={{ mountable_share_drive | default('/dev/sda1') }} 19 | tags: nfs_server 20 | 21 | - name: set mountpoints 22 | mount: name={{ nfsexport }} src={{ mountable_share_drive | default('/dev/sda1') }} fstype=auto opts=defaults,nobootwait dump=0 passno=2 state=mounted 23 | tags: nfs_server 24 | 25 | - name: Ensure NFS utilities are installed. 26 | apt: 27 | name: ['nfs-common','nfs-kernel-server'] 28 | state: present 29 | update_cache: yes 30 | tags: nfs_server 31 | 32 | - name: copy /etc/exports 33 | template: src={{ src_exports }} dest=/etc/exports owner=root group=root 34 | tags: nfs_server 35 | 36 | - name: restart nfs server 37 | service: name=nfs-kernel-server state=restarted 38 | tags: nfs_server 39 | 40 | -------------------------------------------------------------------------------- /artefacts/scripts/config_ansible.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | USER=vagrant 4 | PASSWORD=vagrant 5 | 6 | # wget https://releases.hashicorp.com/packer/1.3.4/packer_1.3.4_linux_amd64.zip 7 | # unzip packer_1.3.4_linux_amd64.zip -d /tmp/packer 8 | # sudo mv /tmp/packer/packer /usr/local/ 9 | # export PATH="$PATH:/usr/local/packer" 10 | # source /etc/environment 11 | 12 | # add addresses to /etc/hosts 13 | echo "192.168.99.155 ansible.sample.com" | sudo tee -a /etc/hosts 14 | echo "192.168.99.154 gitlab.sample.com" | sudo tee -a /etc/hosts 15 | echo "192.168.99.153 jenkins.sample.com" | sudo tee -a /etc/hosts 16 | echo "192.168.99.152 docker.sample.com" | sudo tee -a /etc/hosts 17 | echo "192.168.99.151 nfsclient.sample.com" | sudo tee -a /etc/hosts 18 | echo "192.168.99.150 nfsserver.sample.com" | sudo tee -a /etc/hosts 19 | 20 | echo " " | sudo tee -a /etc/ansible/hosts 21 | echo "[all]" | sudo tee -a /etc/ansible/hosts 22 | echo "gitlab.sample.com" | sudo tee -a /etc/ansible/hosts 23 | echo "jenkins.sample.com" | sudo tee -a /etc/ansible/hosts 24 | echo "docker.sample.com" | sudo tee -a /etc/ansible/hosts 25 | echo "nfsclient.sample.com" | sudo tee -a /etc/ansible/hosts 26 | echo "nfsserver.sample.com" | sudo tee -a /etc/ansible/hosts 27 | 28 | echo " " | sudo tee -a /etc/ansible/hosts 29 | echo "[test]" | sudo tee -a /etc/ansible/hosts 30 | echo "nfsserver.sample.com" | sudo tee -a /etc/ansible/hosts 31 | echo "nfsclient.sample.com" | sudo tee -a /etc/ansible/hosts 32 | 33 | echo " " | sudo tee -a /etc/ansible/hosts 34 | echo "[nfs-server]" | sudo tee -a /etc/ansible/hosts 35 | echo "nfsserver.sample.com" | sudo tee -a /etc/ansible/hosts 36 | 37 | echo " " | sudo tee -a /etc/ansible/hosts 38 | echo "[nfs-clients]" | sudo tee -a /etc/ansible/hosts 39 | echo "nfsclient.sample.com" | sudo tee -a /etc/ansible/hosts 40 | 41 | echo " " | sudo tee -a /etc/ansible/hosts 42 | echo "[jenkins]" | sudo tee -a /etc/ansible/hosts 43 | echo "jenkins.sample.com" | sudo tee -a /etc/ansible/hosts 44 | 45 | echo " " | sudo tee -a /etc/ansible/hosts 46 | echo "[docker]" | sudo tee -a /etc/ansible/hosts 47 | echo "docker.sample.com" | sudo tee -a /etc/ansible/hosts 48 | 49 | echo " " | sudo tee -a /etc/ansible/hosts 50 | echo "[gitlab]" | sudo tee -a /etc/ansible/hosts 51 | echo "gitlab.sample.com" | sudo tee -a /etc/ansible/hosts 52 | 53 | #cat /etc/ansible/hosts 54 | dos2unix ~/artefacts/scripts/ssh_pass.sh 55 | chmod +x ~/artefacts/scripts/ssh_pass.sh 56 | #chown vagrant:vagrant ssh_pass.sh 57 | 58 | # password less authentication using expect scripting language 59 | ~/artefacts/scripts/ssh_pass.sh $USER $PASSWORD "ansible.sample.com" 60 | ~/artefacts/scripts/ssh_pass.sh $USER $PASSWORD "nfsclient.sample.com" 61 | ~/artefacts/scripts/ssh_pass.sh $USER $PASSWORD "nfsserver.sample.com" 62 | ~/artefacts/scripts/ssh_pass.sh $USER $PASSWORD "docker.sample.com" 63 | ~/artefacts/scripts/ssh_pass.sh $USER $PASSWORD "jenkins.sample.com" 64 | ~/artefacts/scripts/ssh_pass.sh $USER $PASSWORD "gitlab.sample.com" 65 | 66 | ansible-playbook ~/artefacts/playbooks/nfs_server.yaml 67 | ansible-playbook ~/artefacts/playbooks/nfs_clients.yaml 68 | ansible-playbook ~/artefacts/playbooks/install_java.yaml 69 | ansible-playbook ~/artefacts/playbooks/install_jenkins.yaml 70 | ansible-playbook ~/artefacts/playbooks/install_docker.yaml 71 | ansible-playbook ~/artefacts/playbooks/install_gitlab.yaml 72 | 73 | 74 | -------------------------------------------------------------------------------- /artefacts/scripts/install_ansible.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Install Ansible repository. 4 | apt -y update && apt-get -y upgrade 5 | apt-get install software-properties-common 6 | apt-add-repository ppa:ansible/ansible -y 7 | 8 | # Install Ansible. 9 | apt-get update 10 | apt-get install ansible -y 11 | 12 | # Install expect, dos2unix & tree 13 | apt-get install expect -y 14 | apt-get install dos2unix -y 15 | apt-get install tree -y 16 | 17 | #apt-get install python-pip -y 18 | 19 | # Installing unzip 20 | # apt-get install unzip -y 21 | 22 | # Cleanup unneded packages 23 | apt-get -y autoremove 24 | 25 | # Adjust timezone to be Singapore 26 | ln -sf /usr/share/zoneinfo/Asia/Singapore /etc/localtime 27 | 28 | # add user to sudo groups 29 | # usermod -aG sudo vagrant 30 | 31 | # lsb_release -a 32 | 33 | # Add vagrant user to sudoers. 34 | echo "vagrant ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers 35 | sed -i "s/^.*requiretty/#Defaults requiretty/" /etc/sudoers 36 | 37 | # Disable daily apt unattended updates. 38 | #echo 'APT::Periodic::Enable "0";' >> /etc/apt/apt.conf.d/10periodic 39 | 40 | # generating password configuration on ansible server to later access remote servers 41 | echo vagrant | sudo -S su - vagrant -c "ssh-keygen -t rsa -f /home/vagrant/.ssh/id_rsa -q -P ''" 42 | 43 | -------------------------------------------------------------------------------- /artefacts/scripts/ssh_pass.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/expect -f 2 | 3 | set host_user [lindex $argv 0] 4 | set host_pass [lindex $argv 1] 5 | set host_name [lindex $argv 2] 6 | 7 | # no need for timeout 1 8 | set timeout 60 9 | 10 | spawn /usr/bin/ssh-copy-id -i /home/vagrant/.ssh/id_rsa.pub $host_user@$host_name 11 | expect { 12 | "*yes/no*" { send "yes\r" ; exp_continue } 13 | "*assword:" { send "$host_pass\r" ; exp_continue } 14 | timeout { exit } 15 | } 16 | -------------------------------------------------------------------------------- /artefacts/templates/exports.j2: -------------------------------------------------------------------------------- 1 | # /etc/exports: the access control list for filesystems which may be exported 2 | # to NFS clients. See exports(5). 3 | # 4 | # Example for NFSv2 and NFSv3: 5 | # /srv/homes hostname1(rw,sync,no_subtree_check) hostname2(ro,sync,no_subtree_check) 6 | # 7 | # Example for NFSv4: 8 | # /srv/nfs4 gss/krb5i(rw,sync,fsid=0,crossmnt,no_subtree_check) 9 | # /srv/nfs4/homes gss/krb5i(rw,sync,no_subtree_check) 10 | # 11 | {{ nfsexport }} {{ hostvars[inventory_hostname]['facter_ipaddress_eth1'] }}/24(rw,sync,no_root_squash,no_subtree_check) 12 | -------------------------------------------------------------------------------- /images/Ansible Provisioning.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ernesen/infra-ansible/3d924203762c5297526c62539a3c348a00299d57/images/Ansible Provisioning.pptx -------------------------------------------------------------------------------- /images/image-01-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ernesen/infra-ansible/3d924203762c5297526c62539a3c348a00299d57/images/image-01-01.png -------------------------------------------------------------------------------- /images/image-01-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ernesen/infra-ansible/3d924203762c5297526c62539a3c348a00299d57/images/image-01-02.png -------------------------------------------------------------------------------- /images/image-01-03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ernesen/infra-ansible/3d924203762c5297526c62539a3c348a00299d57/images/image-01-03.png -------------------------------------------------------------------------------- /images/image-01-04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ernesen/infra-ansible/3d924203762c5297526c62539a3c348a00299d57/images/image-01-04.png -------------------------------------------------------------------------------- /images/image-01-05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ernesen/infra-ansible/3d924203762c5297526c62539a3c348a00299d57/images/image-01-05.png -------------------------------------------------------------------------------- /images/image-01-06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ernesen/infra-ansible/3d924203762c5297526c62539a3c348a00299d57/images/image-01-06.png -------------------------------------------------------------------------------- /install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | clear 4 | echo `date --rfc-3339=seconds` 5 | vagrant up --provider=virtualbox 6 | echo `date --rfc-3339=seconds` --------------------------------------------------------------------------------