The Road to Continuous Deployment (JAX DevOps London 2017)

The Road to Continuous Deployment (JAX DevOps London 2017)

It’s a situation many of us are familiar with: a large legacy, monolithic application, limited or no tests, slow & manual release process, low velocity, no confidence… A lot of refactoring is required, but management keeps pushing for new features.

How to proceed? Using examples and lessons learned from a real-world case, I’ll show you how to replace a legacy application with a modern service-oriented architecture and build a continuous integration and deployment pipeline to deliver value from the first sprint. On the way, we’ll take a look at the process, automated testing, monitoring, master/trunk based development and various tips and best practices.

2f4800411154a8c66dde489448a044d2?s=128

Michiel Rook

April 04, 2017
Tweet

Transcript

  1. 3.
  2. 9.

    FRONTEND MYSQL DB BACKEND LOAD BALANCERS / VARNISH ITBANEN INTERMEDIAIR

    NATIONALEVACATUREBANK FRONTEND FRONTEND FRONTEND BACKEND BACKEND BACKEND MEMCACHE FTP EXT. SERVICES SOLR @michieltcs
  3. 21.

    APPROACH ▸ API first ▸ Services per domain object (job,

    jobseeker, ...) ▸ Migrate individual pages @michieltcs
  4. 25.

    PROXY @michieltcs RewriteEngine On # Serve feature from new service

    for internal network
 RewriteCond expr "%{HTTP:X-FORWARDED-FOR} -ipmatch '192.168.0.0/24'"
 RewriteRule ^/feature/(.*)$ ${NEW_SERVICE_URL}/$1 [P,L] # Proxy everything else to legacy application
 RewriteRule ^/(.*) ${LEGACY_URL}/$1 [P]
 ProxyPassReverse / ${LEGACY_URL}/
  5. 30.

    LEGACY ELASTIC SEARCH DB JOB SERVICE RMQ ITBANEN INTERMEDIAIR NATIONALEVACATUREBANK

    MONGO DB ITBANEN JOBSEEKER SERVICE NVB INTERMEDIAIR @michieltcs
  6. 31.
  7. 33.

    CD?

  8. 46.
  9. 47.
  10. 52.
  11. 54.
  12. 56.
  13. 57.
  14. 62.

    DEFENSE IN DEPTH UNIT TESTS INTEGRATION
 TESTS ACCEPTANCE UI TESTS

    @Test
 public void jobCannotBeFound() {
 when(jobRepository.getById(EXPECTED_JOB_ID))
 .thenReturn(null);
 
 JobService jobService = new JobService(jobRepository);
 
 assertNull(jobService.getById(EXPECTED_JOB_ID));
 verify(jobRepository).getById(EXPECTED_JOB_ID);
 } @michieltcs
  15. 63.

    DEFENSE IN DEPTH UNIT TESTS INTEGRATION
 TESTS ACCEPTANCE
 TESTS UI

    TESTS @Test
 public void shouldFindJob() {
 expectedJob = loadFixture('active_job.yml');
 actualJob = repository.getById(expectedJob.getId());
 
 assertThat(actualJob, isA(Job.class));
 assertEquals(expectedJob.getId(), actualJob.getId());
 } @michieltcs
  16. 64.

    DEFENSE IN DEPTH UNIT TESTS INTEGRATION
 TESTS ACCEPTANCE
 TESTS UI

    TESTS Scenario: Link to related job
 Given a job exists
 And there are related jobs available
 When that job is viewed
 Then a list of related jobs is shown
 And each related job links to the detail page of the related job @michieltcs
  17. 67.
  18. 68.

    CONTINUOUS TESTING UNIT TESTS INTEGRATION TESTS ACCEPTANCE TESTS UI TESTS

    SMOKE
 TESTS Cost Speed Exploratory
 testing Monitoring @michieltcs
  19. 69.

    PIPELINE AS CODE node {
 stage('Run tests') {
 sh "phpunit"


    sh "behat"
 }
 
 stage('Build docker image') {
 sh "docker build -t jobservice:${env.BUILD_NUMBER} ."
 sh "docker push jobservice:${env.BUILD_NUMBER}"
 }
 
 stage('Deploy staging') {
 sh "ansible-playbook -e BUILD=${env.BUILD_NUMBER}
 -i staging deploy.yml"
 }
 
 stage('Deploy production') {
 sh "ansible-playbook -e BUILD=${env.BUILD_NUMBER}
 -i prod deploy.yml"
 }
 } @michieltcs
  20. 70.

    DEPLOYING: ROLLING UPDATE PULL IMAGE START NEW CONTAINER WAIT FOR

    PORT SMOKE TESTS / HEALTH CHECKS ADD NEW CONTAINER TO LB REMOVE OLD CONTAINER FROM LB STOP OLD CONTAINER @michieltcs
  21. 71.

    DEPLOYING PULL IMAGE START NEW CONTAINER WAIT FOR PORT SMOKE

    TESTS / HEALTH CHECKS ADD NEW CONTAINER TO LB REMOVE OLD CONTAINER FROM LB STOP OLD CONTAINER docker pull @michieltcs
  22. 72.

    DEPLOYING PULL IMAGE START NEW CONTAINER WAIT FOR PORT SMOKE

    TESTS / HEALTH CHECKS ADD NEW CONTAINER TO LB REMOVE OLD CONTAINER FROM LB STOP OLD CONTAINER docker run @michieltcs
  23. 73.

    DEPLOYING PULL IMAGE START NEW CONTAINER WAIT FOR PORT SMOKE

    TESTS / HEALTH CHECKS ADD NEW CONTAINER TO LB REMOVE OLD CONTAINER FROM LB STOP OLD CONTAINER wait_for: port=8080 delay=5 timeout=15 @michieltcs
  24. 74.

    DEPLOYING PULL IMAGE START NEW CONTAINER WAIT FOR PORT SMOKE

    TESTS / HEALTH CHECKS ADD NEW CONTAINER TO LB REMOVE OLD CONTAINER FROM LB STOP OLD CONTAINER uri:
 url: http://localhost:8080/health
 status_code: 200
 timeout: 30 @michieltcs
  25. 75.

    DEPLOYING PULL IMAGE START NEW CONTAINER WAIT FOR PORT SMOKE

    TESTS / HEALTH CHECKS ADD NEW CONTAINER TO LB REMOVE OLD CONTAINER FROM LB STOP OLD CONTAINER template: src=haproxy.cfg.j2
 dest=/etc/haproxy/haproxy.cfg service: name=haproxy state=reloaded @michieltcs
  26. 76.

    DEPLOYING PULL IMAGE START NEW CONTAINER WAIT FOR PORT SMOKE

    TESTS / HEALTH CHECKS ADD NEW CONTAINER TO LB REMOVE OLD CONTAINER FROM LB STOP OLD CONTAINER template: src=haproxy.cfg.j2
 dest=/etc/haproxy/haproxy.cfg service: name=haproxy state=reloaded @michieltcs
  27. 77.

    DEPLOYING PULL IMAGE START NEW CONTAINER WAIT FOR PORT SMOKE

    TESTS / HEALTH CHECKS ADD NEW CONTAINER TO LB REMOVE OLD CONTAINER FROM LB STOP OLD CONTAINER docker stop docker rm @michieltcs
  28. 79.
  29. 80.
  30. 83.

    Build per service
 < 10 min. 1 50+ deploys per

    day Reduced number of issues 2 3 @michieltcs
  31. 84.

    Build per service
 < 10 min. 1 50+ deploys per

    day Reduced number of issues Improved page load times 2 3 4 @michieltcs
  32. 87.
  33. 96.

    Reduce cycle times. React faster to the market and test

    product ideas. Make things! We make Agile, DevOps and Continuous Delivery accessible! Hands-on, results- oriented approach to get you where you need to be. Modern infrastructure and pipelines in minutes.