hubertf's NetBSD Blog
Send interesting links to hubert at feyrer dot de!
 
[20130321] Ansible, EC2 and NetBSD final milestone 4 reached: Web and DB on separate VMs in the cloud
In the fourth and last step on my journey to use Ansible to bring a non-trivial system of a Web server and a DB server into Amazon's EC2 cloud, this is the final step. After starting out with a local VMware VM and making first steps with Ansible and EC2, the previous step was to push a single system into the cloud. Now, the final step is to setup two distinct VMs, one for the database and one for the webserver, and then make them known to each other.

The single steps are:

  1. Prepare the two VMs
  2. Basic setup for all systems
  3. Install the database server
  4. Install the webserver
  5. Connect database and webserver
Again, here are all the steps in detail:
  1. As before, ensure local time is correct when talking to Amazon, and also make sure the SSH agent has the proper key loaded.
    % date
    Thu Mar 21 00:45:37 CET 2013
    % ssh-add -l
    2048 d5:25:19:3d:59:40:35:32:03:f7:c5:83:de:19:b6:d0 ../../euca2ools/key-eucaHF.pem (RSA)
    
  2. Make sure security groups are setup properly. We use one group for the database server, and one for the webserver. This defines the access permissions from the internet, and also allows to identify systems for their individual configuration and also for connecting them in the final step:
    % euca-describe-groups
    ...
    GROUP   sg-ae54b3c5     749335780469    ec2-dbservers   Database servers
    PERMISSION      749335780469    ec2-dbservers   ALLOWS  tcp     22      22      FROM    CIDR    0.0.0.0/0
    PERMISSION      749335780469    ec2-dbservers   ALLOWS  tcp     3306    3306    FROM    CIDR    0.0.0.0/0
    PERMISSION      749335780469    ec2-dbservers   ALLOWS  icmp    -1      -1      FROM    CIDR    0.0.0.0/0
    GROUP   sg-a854b3c3     749335780469    ec2-webservers  Web servers
    PERMISSION      749335780469    ec2-webservers  ALLOWS  tcp     22      22      FROM    CIDR    0.0.0.0/0
    PERMISSION      749335780469    ec2-webservers  ALLOWS  tcp     80      80      FROM    CIDR    0.0.0.0/0
    PERMISSION      749335780469    ec2-webservers  ALLOWS  icmp    -1      -1      FROM    CIDR    0.0.0.0/0
    
  3. Now, run our playbook to setup the two VMs. This uses the single playbook from the previous milestone, and just runs it twice with different security groups:
    % ansible-playbook -i hosts-HF config-ec2-prepare-db+web-vm.yml
    
    PLAY [localhost] ********************* 
    
    TASK: [ec2-webservers | Launch new EC2 instance] ********************* 
    changed: [127.0.0.1]
    
    TASK: [ec2-webservers | Give the system 30 seconds to boot up] ********************* 
    changed: [127.0.0.1]
    
    TASK: [ec2-webservers | Get rid of SSH "Are you sure you want to continue connecting (yes/no)?" query] ********************* 
    changed: [127.0.0.1]
    
    TASK: [ec2-webservers | Fix /usr/bootstrap.sh to run pkgin with -y] ********************* 
    changed: [127.0.0.1] => (item={'cmd': 'install /usr/bootstrap.sh /usr/bootstrap.sh.orig'})
    changed: [127.0.0.1] => (item={'cmd': 'chmod +w /usr/bootstrap.sh'})
    changed: [127.0.0.1] => (item={'cmd': 'sed "s,bin/pkgin update,bin/pkgin -y update," /usr/bootstrap.sh'})
    changed: [127.0.0.1] => (item={'cmd': 'chmod -w /usr/bootstrap.sh'})
    
    TASK: [ec2-webservers | Install pkgin via /usr/bootstrap.sh] ********************* 
    changed: [127.0.0.1] => (item={'cmd': u'env PATH=/usr/sbin:${PATH} /usr/bootstrap.sh binpkg'})
    
    TASK: [ec2-webservers | Copy over Ansible binary package] ********************* 
    changed: [127.0.0.1]
    
    TASK: [ec2-webservers | Install Ansible dependencies] ********************* 
    changed: [127.0.0.1]
    
    TASK: [ec2-webservers | Install Ansible package (manually)] ********************* 
    changed: [127.0.0.1]
    
    TASK: [ec2-webservers | Setup lame /usr/bin/python symlink] ********************* 
    changed: [127.0.0.1]
    
    TASK: [ec2-dbservers | Launch new EC2 instance] ********************* 
    changed: [127.0.0.1]
    
    TASK: [ec2-dbservers | Give the system 30 seconds to boot up] ********************* 
    changed: [127.0.0.1]
    
    TASK: [ec2-dbservers | Get rid of SSH "Are you sure you want to continue connecting (yes/no)?" query] ********************* 
    changed: [127.0.0.1]
    
    TASK: [ec2-dbservers | Fix /usr/bootstrap.sh to run pkgin with -y] ********************* 
    changed: [127.0.0.1] => (item={'cmd': 'install /usr/bootstrap.sh /usr/bootstrap.sh.orig'})
    changed: [127.0.0.1] => (item={'cmd': 'chmod +w /usr/bootstrap.sh'})
    changed: [127.0.0.1] => (item={'cmd': 'sed "s,bin/pkgin update,bin/pkgin -y update," /usr/bootstrap.sh'})
    changed: [127.0.0.1] => (item={'cmd': 'chmod -w /usr/bootstrap.sh'})
    
    TASK: [ec2-dbservers | Install pkgin via /usr/bootstrap.sh] ********************* 
    changed: [127.0.0.1] => (item={'cmd': u'env PATH=/usr/sbin:${PATH} /usr/bootstrap.sh binpkg'})
    
    TASK: [ec2-dbservers | Copy over Ansible binary package] ********************* 
    changed: [127.0.0.1]
    
    TASK: [ec2-dbservers | Install Ansible dependencies] ********************* 
    changed: [127.0.0.1]
    
    TASK: [ec2-dbservers | Install Ansible package (manually)] ********************* 
    changed: [127.0.0.1]
    
    TASK: [ec2-dbservers | Setup lame /usr/bin/python symlink] ********************* 
    changed: [127.0.0.1]
    
    PLAY RECAP ********************* 
    127.0.0.1                      : ok=18   changed=18   unreachable=0    failed=0    
    
  4. Just to make sure, check that the two instances run properly, and are in the right security groups, ec2-webservers and ec2-dbservers:
    % euca-describe-instances
    RESERVATION     r-a419f9d9      749335780469    ec2-webservers
    INSTANCE        i-21b7c441      ami-5d0f8034    ...
    RESERVATION     r-641efe19      749335780469    ec2-dbservers
    INSTANCE        i-54a2ab3e      ami-5d0f8034    ...
    
  5. Next, bring the two freshly setup systems (which are already capable of acting as ansible targets) up to our basic system setup:
    % env ANSIBLE_HOSTS=./ec2.py ansible-playbook config-ec2-basic.yml
    
    PLAY [security_group_ec2-webservers;security_group_ec2-dbservers] ********************* 
    
    TASK: [ping] ********************* 
    ok: [ec2-54-235-44-118.compute-1.amazonaws.com]
    ok: [ec2-54-234-139-151.compute-1.amazonaws.com]
    
    TASK: [Install tcsh] ********************* 
    changed: [ec2-54-235-44-118.compute-1.amazonaws.com]
    changed: [ec2-54-234-139-151.compute-1.amazonaws.com]
    
    TASK: [Add user feyrer] ********************* 
    changed: [ec2-54-234-139-151.compute-1.amazonaws.com]
    changed: [ec2-54-235-44-118.compute-1.amazonaws.com]
    
    TASK: [Create ~feyrer/.ssh directory] ********************* 
    changed: [ec2-54-235-44-118.compute-1.amazonaws.com]
    changed: [ec2-54-234-139-151.compute-1.amazonaws.com]
    
    TASK: [Enable ssh login with ssh-key] ********************* 
    changed: [ec2-54-235-44-118.compute-1.amazonaws.com]
    changed: [ec2-54-234-139-151.compute-1.amazonaws.com]
    
    TASK: [Install sudo] ********************* 
    changed: [ec2-54-235-44-118.compute-1.amazonaws.com]
    changed: [ec2-54-234-139-151.compute-1.amazonaws.com]
    
    TASK: [Enable PW-less sudo-access for everyone in group 'wheel'] ********************* 
    changed: [ec2-54-234-139-151.compute-1.amazonaws.com]
    changed: [ec2-54-235-44-118.compute-1.amazonaws.com]
    
    TASK: [Disable ssh logins as root] ********************* 
    ok: [ec2-54-235-44-118.compute-1.amazonaws.com]
    ok: [ec2-54-234-139-151.compute-1.amazonaws.com]
    
    PLAY RECAP ********************* 
    ec2-54-234-139-151.compute-1.amazonaws.com : ok=8    changed=6    unreachable=0    failed=0    
    ec2-54-235-44-118.compute-1.amazonaws.com : ok=8    changed=6    unreachable=0    failed=0    
    
  6. Check:
    % ssh ec2-54-234-139-151.compute-1.amazonaws.com id
    uid=1000(feyrer) gid=100(users) groups=100(users),0(wheel)
    % 
    % ssh ec2-54-235-44-118.compute-1.amazonaws.com id
    uid=1000(feyrer) gid=100(users) groups=100(users),0(wheel)
    
  7. Now that the two machines run with our basline configuration, install their individual software and settings. First the database server:
    % env ANSIBLE_HOSTS=./ec2.py ansible-playbook config-ec2-dbserver.yml
    
    PLAY [security_group_ec2-dbservers] ********************* 
    
    TASK: [Install mysql] ********************* 
    changed: [ec2-54-235-44-118.compute-1.amazonaws.com]
    
    TASK: [Install MySQL rc.d script] ********************* 
    changed: [ec2-54-235-44-118.compute-1.amazonaws.com]
    
    TASK: [Start MySQL service] ********************* 
    changed: [ec2-54-235-44-118.compute-1.amazonaws.com]
    
    TASK: [Install python-mysqldb (for mysql_user module)] ********************* 
    changed: [ec2-54-235-44-118.compute-1.amazonaws.com]
    
    TASK: [Setup DB] ********************* 
    changed: [ec2-54-235-44-118.compute-1.amazonaws.com]
    
    TASK: [Add db-user] ********************* 
    changed: [ec2-54-235-44-118.compute-1.amazonaws.com]
    
    TASK: [Copy over DB template] ********************* 
    changed: [ec2-54-235-44-118.compute-1.amazonaws.com]
    
    TASK: [Import DB data] ********************* 
    changed: [ec2-54-235-44-118.compute-1.amazonaws.com]
    
    PLAY RECAP ********************* 
    ec2-54-235-44-118.compute-1.amazonaws.com : ok=8    changed=8    unreachable=0    failed=0    
    
    
    
  8. Check and see if the database works as expected:
    % ssh -t ec2-54-235-44-118.compute-1.amazonaws.com mysql -u webapp -p webapp
    Enter password: ****
    ...
    mysql> show tables;
    +------------------+
    | Tables_in_webapp |
    +------------------+
    | names            |
    +------------------+
    1 row in set (0.01 sec)
    
    mysql> select * from names;
    +----+--------+------+
    | id | first  | last |
    +----+--------+------+
    |  1 | Donald | Duck |
    |  2 | Daisy  | Duck |
    +----+--------+------+
    2 rows in set (0.00 sec)
    
    mysql> bye
    
  9. Excellent. Now setup the webserver, too:
      
    % env ANSIBLE_HOSTS=./ec2.py ansible-playbook config-ec2-webserver.yml
    
    PLAY [security_group_ec2-webservers] ********************* 
    
    TASK: [Installing ap24-php53 package and dependencies] ********************* 
    changed: [ec2-54-234-139-151.compute-1.amazonaws.com]
    
    TASK: [Install Apache rc.d script] ********************* 
    changed: [ec2-54-234-139-151.compute-1.amazonaws.com]
    
    TASK: [Enable and start Apache service] ********************* 
    changed: [ec2-54-234-139-151.compute-1.amazonaws.com]
    
    TASK: [Enable PHP in Apache config file] ********************* 
    changed: [ec2-54-234-139-151.compute-1.amazonaws.com] => (item={'re': 'LoadModule.*mod_php5.so', 'l': 'LoadModule php5_module lib/httpd/mod_php5.so'})
    changed: [ec2-54-234-139-151.compute-1.amazonaws.com] => (item={'re': 'AddHandler.*x-httpd-php', 'l': 'AddHandler application/x-httpd-php .php'})
    
    TASK: [Make Apache read index.php] ********************* 
    changed: [ec2-54-234-139-151.compute-1.amazonaws.com]
    
    TASK: [Add simple PHP test - see http://10.0.0.181/phptest.php] ********************* 
    changed: [ec2-54-234-139-151.compute-1.amazonaws.com]
    
    TASK: [Install phpmyadmin] ********************* 
    changed: [ec2-54-234-139-151.compute-1.amazonaws.com]
    
    TASK: [Enable phpmyadmin in Apache config] ********************* 
    changed: [ec2-54-234-139-151.compute-1.amazonaws.com]
    
    TASK: [Fix Apache access control for phpmyadmin] ********************* 
    changed: [ec2-54-234-139-151.compute-1.amazonaws.com]
    
    TASK: [Enable PHP modules in PHP config file] ********************* 
    changed: [ec2-54-234-139-151.compute-1.amazonaws.com] => (item={'re': '^extension.*zlib.so', 'l': 'extension=zlib.so'})
    changed: [ec2-54-234-139-151.compute-1.amazonaws.com] => (item={'re': '^extension.*zip.so', 'l': 'extension=zip.so'})
    changed: [ec2-54-234-139-151.compute-1.amazonaws.com] => (item={'re': '^extension.*mysqli.so', 'l': 'extension=mysqli.so'})
    changed: [ec2-54-234-139-151.compute-1.amazonaws.com] => (item={'re': '^extension.*mysql.so', 'l': 'extension=mysql.so'})
    changed: [ec2-54-234-139-151.compute-1.amazonaws.com] => (item={'re': '^extension.*mcrypt.so', 'l': 'extension=mcrypt.so'})
    changed: [ec2-54-234-139-151.compute-1.amazonaws.com] => (item={'re': '^extension.*mbstring.so', 'l': 'extension=mbstring.so'})
    changed: [ec2-54-234-139-151.compute-1.amazonaws.com] => (item={'re': '^extension.*json.so', 'l': 'extension=json.so'})
    changed: [ec2-54-234-139-151.compute-1.amazonaws.com] => (item={'re': '^extension.*gd.so', 'l': 'extension=gd.so'})
    changed: [ec2-54-234-139-151.compute-1.amazonaws.com] => (item={'re': '^extension.*gettext.so', 'l': 'extension=gettext.so'})
    changed: [ec2-54-234-139-151.compute-1.amazonaws.com] => (item={'re': '^extension.*bz2.so', 'l': 'extension=bz2.so'})
    
    TASK: [Create directory for webapp] ********************* 
    changed: [ec2-54-234-139-151.compute-1.amazonaws.com]
    
    TASK: [Deploy example webapp] ********************* 
    changed: [ec2-54-234-139-151.compute-1.amazonaws.com]
    
    TASK: [Create webapp symlink for easy access] ********************* 
    changed: [ec2-54-234-139-151.compute-1.amazonaws.com]
    
    NOTIFIED: [restart apache] ********************* 
    changed: [ec2-54-234-139-151.compute-1.amazonaws.com]
    
    PLAY RECAP ********************* 
    ec2-54-234-139-151.compute-1.amazonaws.com : ok=14   changed=14   unreachable=0    failed=0    
    
  10. Again, test:
    % links -dump ec2-54-234-139-151.compute-1.amazonaws.com/
                                       It works!
    %
    % links -dump http://ec2-54-234-139-151.compute-1.amazonaws.com/phptest.php | head
       PHP Logo                                                                   
                                                                                  
                                   PHP Version 5.3.17                             
    
       System          NetBSD ip-10-80-61-33.ec2.internal 6.0.1 NetBSD 6.0.1      
                       (XEN3PAE_DOMU) i386                                        
       Build Date      Dec 14 2012 10:31:13                                       
                       './configure' '--with-config-file-path=/usr/pkg/etc'       
                       '--with-config-file-scan-dir=/usr/pkg/etc/php.d'           
                       '--sysconfdir=/usr/pkg/etc' '--localstatedir=/var'         
    % 
    % links -dump http://ec2-54-234-139-151.compute-1.amazonaws.com/webapp/
       Showing table hf.names:
    
       Cannot connect to database: Can't connect to local MySQL server through
       socket '/tmp/mysql.sock' (2)(2002)
    
  11. Close to optimum, but the last error is actually expectet: In order for proper operation, the Database needs to grant the webserver access, and the web server needs to know where the database server is. So let's connect them!

    This step is done by preparing a shell script on both systems, which will then be ran to - depending on the system's security group - perform the proper steps:

    % env ANSIBLE_HOSTS=./ec2.py ansible-playbook config-ec2-connections.yml
    
    PLAY [security_group_ec2-webservers;security_group_ec2-dbservers] ********************* 
    
    TASK: [Collect EC2 host information] ********************* 
    ok: [ec2-54-234-139-151.compute-1.amazonaws.com]
    ok: [ec2-54-235-44-118.compute-1.amazonaws.com]
    
    TASK: [Prepare connection-script in /tmp/do-connect-vms.sh] ********************* 
    changed: [ec2-54-234-139-151.compute-1.amazonaws.com]
    changed: [ec2-54-235-44-118.compute-1.amazonaws.com]
    
    TASK: [Run connection-script] ********************* 
    changed: [ec2-54-234-139-151.compute-1.amazonaws.com]
    changed: [ec2-54-235-44-118.compute-1.amazonaws.com]
    
    PLAY RECAP ********************* 
    ec2-54-234-139-151.compute-1.amazonaws.com : ok=3    changed=2    unreachable=0    failed=0    
    ec2-54-235-44-118.compute-1.amazonaws.com : ok=3    changed=2    unreachable=0    failed=0    
    
  12. With that final step, our test web application works, and the webserver can access the database properly:
    % links -dump http://ec2-54-234-139-151.compute-1.amazonaws.com/webapp/
       Showing table hf.names:
    
       +--------------------+
       | id | first  | last |
       |----+--------+------|
       | 1  | Donald | Duck |
       |----+--------+------|
       | 2  | Daisy  | Duck |
       +--------------------+
    
         ----------------------------------------------------------------------
    
       Enter new values:
    
       first:     _____________________ 
       last:      _____________________ 
       [ Submit ] 
    
So much for this exercise. I'll talk about the ansible and euca2ools packages at pkgsrcCon 2013 in Berlin. Join in if you're curious about what the actual playbooks used in the above examples look like, or stay tuned to find my presentation and all the data after pkgsrcCon 2013.

[Tags: , , , ]


Disclaimer: All opinion expressed here is purely my own. No responsibility is taken for anything.

Access count: 34937045
Copyright (c) Hubert Feyrer