Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Using Fabric and Docker for deployment testing

Using Fabric and Docker for deployment testing

"Using Fabric and Docker for deployment testing". Slide of my presentation @ PyCon APAC 2014, Taiwan. [*]

[*] https://tw.pycon.org/2014apac

Cheng-Lung Sung

May 18, 2014
Tweet

More Decks by Cheng-Lung Sung

Other Decks in Technology

Transcript

  1. • Motivation • Fabric Introduction • Introduction to Docker •

    Fabric + Docker for deployment testing Outline
  2. • Developers use Mac • brew install ... • Development

    site is Ubuntu • apt-get install ...
  3. • Developer use Mac • Development site is Ubuntu •

    Production site is CentOS • yum install ...
  4. • Developer use Mac • Development site is Ubuntu •

    Production site is CentOS • Demo site is Windows • Windows Update
  5. Fabric from README • Fabric is a Python (2.5-2.7) library

    and command-line tool for streamlining the use of SSH for application deployment or systems administration tasks.
  6. --- a/pep-0373.txt +++ b/pep-0373.txt +Update +====== + +The End Of

    Life date (EOL, sunset date) for Python 2.7 has been moved +five years into the future, to 2020. This decision was made to +clarify the status of Python 2.7 and relieve worries for those users +who cannot yet migrate to Python 3. See also PEP 466. + +This declaration does not guarantee that bugfix releases will be made +on a regular basis, but it should enable volunteers who want to +contribute bugfixes for Python 2.7 and it should satisfy vendors who +still have to support Python 2 for years to come. + +There will be no Python 2.8. + Release Manager and Crew ======================== @@ -50,15 +65,16 @@ Maintenance releases
  7. Fabric is • A tool that lets you execute arbitrary

    Python functions via the command line; • A library of subroutines (built on top of a lower-level library) to make executing shell commands over SSH easy and Pythonic.
  8. Fabric Features • execute local() or run() remote shell commands

    (via ssh) • parallel execution (via multiprocessing) • prompt input and managed output • abort execution • define tasks
  9. from fabric.contrib.console import confirm def coverage(): local('coverage erase') local('coverage run

    ./manage.py test') local("coverage report --omit='*/site-packages/*'") local("coverage html --omit='*/site-packages/*'") def pre_commit(): create_folder() with settings(warn_only=True): result = local('./manage.py test', capture=True) if result.failed and \ not confirm("Tests failed. Continue anyway?"): abort("Aborting at user request.") coverage()
  10. Fabric Environment • Environment as configuration (dict, fabric.state.env) • env.host,

    env.password • env.hosts (list), env.passwords (dict) • env.port • env.local_user, env.user • env.roledefs (dict of name to host list mapping) • The settings context manager • with settings(warn_only=true):
  11. Fabric Execution model • Execution strategy • A list of

    tasks is created • For each task, a task-specific host list is generated from various sources • The task list is walked through in order, and each task if run once per host in its hosts list • Tasks with no hosts in their host list are considered local-only, and will alway run once and only onces
  12. from fabric.api import run, task, env def set_hosts(): env.hosts =

    ['dev.clsung.tw', 'linode.clsung.tw'] def task(): run('uname -s') $ fab task No hosts found. Please specify (single) host string for connection: $ fab set_hosts task [dev.clsung.tw] Executing task 'task' [dev.clsung.tw] run: uname -s [dev.clsung.tw] out: Linux [dev.clsung.tw] out: [linode.clsung.tw] Executing task 'task' [linode.clsung.tw] run: uname -s [linode.clsung.tw] out: Linux [linode.clsung.tw] out:
  13. Fabric @roles from fabric.api import task, env, run, roles env.roledefs

    = { 'db': ['linode.clsung.tw'], 'dev': ['dev.clsung.tw'], } @roles('db') def task(): run('uname -s')
  14. "It worked yesterday." “昨天還是好的啊“ "You must have the wrong version."

    “你⼀一定是⽤用到舊版了“ "THIS can't be the source of THAT." “這個不可能是那個的原始碼” "It works, but it hasn't been tested." “這程式應該是會動的,只是我寫好後還沒做測試。” "It works on my machine.” “在我的機器明明就是好的”
  15. • Resource Allocation in VM setting • CPU, RAM •

    Preallocated disk, .. • The modification is recorded • Boot once, test twice, result changes • If always use fresh image • And always re-run the whole setup process
  16. LinuX Container(LXC) • Run a Linux system within another Linux

    system • Isolated environment for processes in the container • From inside, like a VM • From outside, like a normal process • “chroot on steroids”
  17. # A basic apache server. To use either add or

    bind mount content under /var/www FROM ubuntu:12.04 MAINTAINER Kimbro Staken version: 0.1 RUN apt-get update && \ apt-get install -y apache2 && \ apt-get clean && \ rm -rf /var/lib/apt/lists/* ENV APACHE_RUN_USER www-data ENV APACHE_RUN_GROUP www-data ENV APACHE_LOG_DIR /var/log/apache2 EXPOSE 80 CMD ["/usr/sbin/apache2", "-D", "FOREGROUND"]
  18. $ fab build [localhost] local: docker build . Uploading context

    3.584 kB Uploading context Step 0 : FROM phusion/baseimage ---> 35c2d5a269ff Step 1 : ENV HOME /root ---> Using cache ---> 50937eb28ee8 .... Successfully built 532a5f458a34
  19. # VERSION 0.0.1 FROM centos:latest MAINTAINER Cheng-Lung Sung <[email protected]> #

    Enviroment ENV HOME /root ENV GOPATH /root/go ENV GOROOT /root/hg/go ENV PATH /root/go/bin:/root/hg/go/bin:/usr/local/bin:/usr/local/sbin:/usr/sbin:/usr/bin:/sbin:/ bin # for source code RUN mkdir -p /root/go/src/clsung.tw # Development tools RUN rpm -Uvh http://dl.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm RUN yum -y groupinstall "Development Tools" RUN yum -y python pip # build Go RUN cd /root/go/src/clsung.tw && git clone https://github.com/clsung/django_poster RUN cd /root/go/src/clsung.tw && pip -r requirement.txt # set working directory (entrypoint root) WORKDIR /root/go/src/clsung.tw/django_poster ENTRYPOINT ['./manage.py', 'runserver']
  20. Notes on MacOSX • Require boot2docker (linux) • VOLUME is

    useless on MacOSX • docker cp in running container • use vagrant
  21. • Replace virtualenv with docker in testing • Use docker

    to test backend (web and db) • After testing, convert Dockerfile to Salt File • Before docker 1.0 released Goal
  22. run docker command in fabric @task def docker(cmd): """ Run

    Docker cmd """ return run("docker %s" % cmd)
  23. clean container by name @task def clean_env(): with settings(warn_only=True): docker('kill

    simplehttpd') docker('rm simplehttpd') docker('rm client')
  24. build images @task def build(): docker_ids = {} for d

    in ['httpd', 'client']: with lcd(d): result =local('docker build .', capture=True) # handy hacks: get the image id docker_ids[d] = result.stdout.split()[-1] return docker_ids
  25. @task def pre_deploy(): clean_env() d_ids = build() docker('run --name simplehttpd

    -d {0}'.format( d_ids['httpd'])) with settings(warn_only=True): result = docker('run -i --rm --link simplehttpd:httpd ' '--name "client" {0}'.format( d_ids['client']), capture=True) if result.failed and not confirm("Tests failed. Continue anyway?"): abort("Aborting at user request.") logger.info(result.stdout) docker('kill simplehttpd')
  26. FROM phusion/baseimage ENV HOME /root RUN /etc/my_init.d/00_regen_ssh_host_keys.sh CMD ["/sbin/my_init"] RUN

    apt-get update RUN apt-get install -y python EXPOSE 8000 ENTRYPOINT ["python", "-m", "SimpleHTTPServer", "8000"] httpd/Dockerfile
  27. client/Dockerfile FROM phusion/baseimage ENV HOME /root RUN apt-get update RUN

    apt-get install -y python python-pip RUN pip install requests ADD ping.py /opt/ping.py CMD ["/usr/bin/python", "/opt/ping.py"]
  28. $ fab pre_deploy [localhost] local: docker build . [localhost] local:

    docker run --name simplehttpd -d b6c6ab6afc4d 9c2515094c384099a4d867747e0a9de2f72b0244e86f0263b559e555 98dd4239 [localhost] local: docker run -i --rm --link simplehttpd:httpd --name "client" f546ae5530c5 INFO:fabfile:200 [localhost] local: docker kill simplehttpd simplehttpd Done.
  29. if any error..... [localhost] local: docker build . [localhost] local:

    docker run --name simplehttpd -d b6c6ab6afc4d 97da8851573380116f83b9f11f7a884591ebfffa53875ce91defd7810359ba7b [localhost] local: docker run -i --rm --link simplehttpd:httpd --name "client" cc5951661843 Warning: local() encountered an error (return code 1) while executing 'docker run -i --rm --link simplehttpd:httpd --name "client" cc5951661843' Tests failed. Continue anyway? [Y/n] n Fatal error: Aborting at user request. Aborting.
  30. Other • Shipper - fabric for docker • https://github.com/mailgun/shipper •

    easy to move containers from a developer environment to a staging environment