Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Hands on Docker - Launch your own LEMP or LAMP stack - SunshinePHP

261 views

Published on

In this tutorial we will go over setting up a standard LEMP stack for development use and learn how to modify it to mimic your production/pre-production environments as closely as possible. We will go over how to switch from Nginx to Apache, upgrade PHP versions and introduce additional storage engines such as Redis to the equation. We'll also step through how to run both unit and acceptance suites using headless Selenium images in the stack. Leave here fully confident in knowing that whatever environment you get thrown into, you can replicate it and work in it comfortably.

Published in: Internet
  • Be the first to comment

Hands on Docker - Launch your own LEMP or LAMP stack - SunshinePHP

  1. 1. @danaluther Hands on Docker: Launch Your Own LEMP or LAMP Stack Dana Luther https://git.io/JvUy5 https://joind.in/talk/d1bc3
  2. 2. @danaluther What are we going to do today, Brain? Set up standard LAMP and LEMP stacks using Docker stack Modify the stack to mimic production Run codeception test suites against our application Learn how to swap out php versions Add and remove additional services
  3. 3. @danaluther Where are you on your Docker journey? Brand new to this rodeo… Docker containers are my jam! I am Docker.
  4. 4. @danaluther Everyone set up and ready? Docker Desktop installed and running Checked out the GIT repo Pulled the docker images Anyone using Windows? Set to use LCOW?
  5. 5. @danaluther Moving beyond containers…
  6. 6. @danaluther Moving beyond containers… Image Container Service Stack
  7. 7. @danaluther Moving beyond containers… Image Container Service Stack App
  8. 8. @danaluther Moving beyond containers… Image Container Service Stack App
  9. 9. @danaluther Release the swarm! > docker swarm init
  10. 10. @danaluther Basic LAMP Stack docker-compose.yml php:7.4-apache mysql 01_LAMP
  11. 11. @danaluther Basic LAMP Stack version: "3.7" services: php: # https: //hub.docker.com/_/php image: php:7.4-apache ports: - 80:80 volumes: - ./src:/var/ www/html db: image: mysql environment: - MYSQL_ROOT_PASSWORD_FILE=/run/secrets/db_pwd secrets: - db_pwd secrets: db_pwd: file: ./root_db_password.txt docker-compose.yml 01_LAMP
  12. 12. SIDEBAR: @danaluther https://docs.docker.com/compose/compose-file/ Docker compose file reference
  13. 13. @danaluther Basic LAMP Stack version: "3.7" services: php: # https: //hub.docker.com/_/php image: php:7.4-apache ports: - 80:80 volumes: - ./src:/var/ www/html db: image: mysql environment: - MYSQL_ROOT_PASSWORD_FILE=/run/secrets/db_pwd secrets: - db_pwd secrets: db_pwd: file: ./root_db_password.txt docker-compose.yml 01_LAMP
  14. 14. SIDEBAR: @danaluther What’s in a secret?
  15. 15. @danaluther Basic LAMP Stack > docker stack deploy -c docker-compose.yml hod Make sure you are on the 01_LAMP branch of the workshop repo 01_LAMP
  16. 16. @danaluther Basic LAMP Stack > docker stack deploy -c docker-compose.yml hod Make sure you are on the 01_LAMP branch of the workshop repo 01_LAMP
  17. 17. @danaluther Verify the services have all launched > docker service ls 01_LAMP
  18. 18. @danaluther Verify the services have all launched > docker service ls 01_LAMP
  19. 19. SIDEBAR: @danaluther Stuck and not sure what the problem is? > docker stack ps hod --no-trunc
  20. 20. @danaluther Verify the services have all launched > docker service ls 01_LAMP
  21. 21. @danaluther Verify the services have all launched > docker service ls 01_LAMP
  22. 22. ⚠ Common “Gotcha” @danaluther No public port for MySQL unless you *want* to expose it externally.
  23. 23. @danaluther01_LAMP
  24. 24. @danaluther01_LAMP
  25. 25. SIDEBAR: @danaluther What’s in a stock PHP image? > docker run --rm php:7.4-fpm php-fpm -m
  26. 26. SIDEBAR: @danaluther What’s in a stock PHP image?
  27. 27. @danaluther Creating our custom PHP image Add the mysqli and PDO_mysql extensions Use build args in the Dockerfile ARG PHP_TARGET=7.4-apache FROM php:$PHP_TARGET RUN docker-php-ext-install -j$(nproc) mysqli pdo_mysql 02_LAMP
  28. 28. @danaluther Enabling Buildkit https://docs.docker.com/develop/develop-images/build_enhancements/
  29. 29. @danaluther Creating our custom PHP image > docker image build -f Dockerfile-php-mysql -t dhluther/php:7.4-apache-mysql . From the /images/ directory: 02_LAMP
  30. 30. @danaluther Creating our custom PHP image > docker image build -f Dockerfile-php-mysql -t dhluther/php:7.4-apache-mysql . From the /images/ directory: 02_LAMP
  31. 31. @danaluther Update our LAMP stack version: "3.7" services: php: # Custom PHP Image - see /images/Readme.md image: dhluther/php:7.4-apache-mysql ports: - 80:80 volumes: - ./src:/var/ www/html db: image: mysql environment: - MYSQL_ROOT_PASSWORD_FILE=/run/secrets/db_pwd secrets: - db_pwd secrets: db_pwd: file: ./root_db_password.txt 02_LAMP
  32. 32. @danaluther Re-deploy the LAMP stack > docker stack deploy -c docker-compose.yml hod
  33. 33. @danaluther Re-deploy the LAMP stack > docker stack deploy -c docker-compose.yml hod
  34. 34. @danaluther02_LAMP
  35. 35. @danaluther <? /** * mysql-check.php */ try { $db = new PDO('mysql:host=db', 'root', 'sup3rs3cr3tp4ssw0rd'); echo 'MySQL Version: ', $db ->getAttribute(PDO ::ATTR_CLIENT_VERSION); } catch (Exception $e) { echo 'Aw shucks pardner, ', $e ->getMessage(); } 02_LAMP
  36. 36. @danaluther Checking the service logs 02_LAMP > docker service logs hod_php
  37. 37. @danaluther Checking the service logs 02_LAMP > docker service logs hod_php
  38. 38. @danaluther Take the stack down 02_LAMP > docker stack rm hod
  39. 39. @danaluther Basic LEMP Stack docker-compose.yml php:7.4-fpm mysql nginx 03_LEMP
  40. 40. @danaluther Basic LEMP Stack 03_LEMP version: "3.7" services: php: image: dhluther/php:7.4-fpm-mysql volumes: - ./src:/var/ www/html …db… web: image: nginx ports: - 80:80 - 443:443 volumes: - ./src:/var/ www/html configs: - source: nginx-conf target: /etc/nginx/conf.d/default.conf secrets: db_pwd: file: ./root_db_password.txt configs: nginx-conf: file: ./nginx/default.conf
  41. 41. @danaluther Creating our custom PHP-FPM image > docker image build -f Dockerfile-php-mysql -t dhluther/php:7.4-fpm-mysql . --build-arg PHP_TARGET=7.4-fpm From the /images/ directory: 03_LEMP
  42. 42. @danaluther03_LEMP
  43. 43. @danaluther Deploy the LEMP stack > docker stack deploy -c docker-compose.yml hod 03_LEMP
  44. 44. @danaluther03_LEMP
  45. 45. @danaluther03_LEMP
  46. 46. @danaluther03_LEMP
  47. 47. ⚠ Common “Gotcha” @danaluther NO PERSISTENT DATA! 03_LEMP
  48. 48. ⚠ Common “Gotcha” @danaluther db: image: mysql environment: - MYSQL_ROOT_PASSWORD_FILE=/run/secrets/db_pwd secrets: - db_pwd NO PERSISTENT DATA! 03_LEMP
  49. 49. ⚠ Common “Gotcha” @danaluther PERSISTENT DATA! 04_LEMP
  50. 50. ⚠ Common “Gotcha” @danaluther db: image: mysql environment: - MYSQL_ROOT_PASSWORD_FILE=/run/secrets/db_pwd volumes: - ./data:/var/lib/mysql secrets: - db_pwd PERSISTENT DATA! 04_LEMP
  51. 51. @danaluther Fresh deploy the Stack 04_LEMP > docker stack rm hod > docker stack deploy -c docker-compose.yml hod > docker network ls
  52. 52. @danaluther Quick Break - Stretch!
  53. 53. @danaluther The stack is standard, but are we?
  54. 54. @danaluther The stack is standard, but are we? Customized config files: php.ini and php.conf my.conf nginx.conf
  55. 55. @danaluther The stack is standard, but are we? Customized config files: php.ini and php.conf my.conf nginx.conf Customized images: my/php my/mysql my/nginx
  56. 56. @danaluther Basic LEMP Stack (flashback) 03_LEMP version: "3.7" services: php: image: dhluther/php:7.4-fpm-mysql volumes: - ./src:/var/ www/html …db… web: image: nginx ports: - 80:80 - 443:443 volumes: - ./src:/var/ www/html configs: - source: nginx-conf target: /etc/nginx/conf.d/default.conf secrets: db_pwd: file: ./root_db_password.txt configs: nginx-conf: file: ./nginx/default.conf
  57. 57. @danaluther What’s in the default nginx.conf? > docker run --rm nginx cat /etc/nginx/nginx.conf
  58. 58. @danaluther
  59. 59. @danaluther05_LEMP # Max file size for uploads client_max_body_size 20m; # Sets the cache for 1k items for 1 minute open_file_cache max=1000 inactive=20s; open_file_cache_valid 60s; open_file_cache_min_uses 5; open_file_cache_errors off; # GZIP compression settings, text/html is automatically compressed gzip on; gzip_disable "msie6"; gzip_vary on; gzip_comp_level 5; gzip_buffers 16 8k; gzip_min_length 350; gzip_proxied any; gzip_types application/atom+xml application/rss+xml application/x-javascript application/javascript application/json text/plain text/css text/x- component text/x-cross-domain-policy text/javascript; # disable auto-index across the board by default autoindex off; # disable server side includes by default ssi off;
  60. 60. @danaluther Update NGiNX configs 05_LEMP version: "3.7" services: php: image: dhluther/php:7.4-fpm-mysql volumes: - ./src:/var/ www/html …db… web: … configs: - source: nginx-conf target: /etc/nginx/conf.d/default.conf - source: nginx-base—conf target: /etc/nginx/nginx.conf secrets: db_pwd: file: ./root_db_password.txt configs: nginx-conf: file: ./nginx/default.conf nginx-base-conf: file: ./nginx/nginx.conf
  61. 61. @danaluther What’s in our PHP config?
  62. 62. @danaluther What might you need to customize? Timezone setting Error reporting Output caching and buffering Listen directives Ping/Status directives Timeouts and extension limitations
  63. 63. @danaluther Create custom .ini and .conf files tz.ini — /usr/local/etc/php/conf.d/ custom.ini — /usr/local/etc/php/conf.d/ www.mysite.conf — /usr/local/etc/php-fpm.d/ 05_LEMP
  64. 64. @danaluther Update php image Dockerfile 05_LEMP
  65. 65. @danaluther Build the php image > docker image build -f Dockerfile-php-mysql -t dhluther/php:7.4-fpm-mysql-c --target=customized . --build-arg PHP_TARGET=7.4-fpm 05_LEMP
  66. 66. @danaluther Build the php image 05_LEMP
  67. 67. @danaluther Update compose with new php image php: # Custom PHP Image - see /images/Readme.md image: dhluther/php:7.4-fpm-mysql-c volumes: - ./src:/var/www/html
  68. 68. @danaluther Deploy stack updates > docker stack deploy -c docker-compose.yml hod
  69. 69. @danaluther Deploy stack updates > docker stack deploy -c docker-compose.yml hod
  70. 70. @danaluther Verify ini files loaded
  71. 71. @danaluther Quick Break - Get some water!
  72. 72. @danaluther Great - we match production. But what about testing??
  73. 73. @danaluther Add xdebug and blackfire probe 07_LEMP
  74. 74. @danaluther (the full xdebug install commands) 07_LEMP RUN yes | pecl install xdebug && echo "zend_extension=$(find /usr/local/lib/php/extensions/ -name xdebug.so)" > $PHP_INI_DIR/conf.d/xdebug.ini && echo "xdebug.remote_enable=on" >> $PHP_INI_DIR/conf.d/xdebug.ini && echo "xdebug.remote_autostart=off" >> $PHP_INI_DIR/conf.d/xdebug.ini EXPOSE 8080 80 9000 9001
  75. 75. @danaluther Build the debug image 07_LEMP > docker image build -f Dockerfile-php-mysql -t dhluther/php:7.4-debug --target=debug . --build-arg PHP_TARGET=7.4-fpm
  76. 76. @danaluther Build the debug image 07_LEMP > docker image build -f Dockerfile-php-mysql -t dhluther/php:7.4-debug --target=debug . --build-arg PHP_TARGET=7.4-fpm
  77. 77. @danaluther Build the debug image 07_LEMP > docker image build -f Dockerfile-php-mysql -t dhluther/php:7.4-debug --target=debug . --build-arg PHP_TARGET=7.4-fpm
  78. 78. SIDEBAR: @danaluther https://blackfire.io/docs/integrations/docker blackfire: image: blackfire/blackfire ports: - "8707:8707" environment: # Tokens for your account - BLACKFIRE_CLIENT_ID=<insert id here> - BLACKFIRE_CLIENT_TOKEN=<insert token here> # Tokens for your environment - BLACKFIRE_SERVER_ID=<insert id here> - BLACKFIRE_SERVER_TOKEN=<insert token here> - BLACKFIRE_LOG_LEVEL=4
  79. 79. @danaluther Deploy stack updates > docker stack deploy -c docker-compose.yml hod 07_LEMP
  80. 80. @danaluther Deploy stack updates > docker stack deploy -c docker-compose.yml hod 07_LEMP
  81. 81. @danaluther07_LEMP
  82. 82. @danaluther07_LEMP
  83. 83. @danaluther07_LEMP
  84. 84. SIDEBAR: @danaluther Support the tools you use https://www.patreon.com/derickr
  85. 85. @danaluther What and how do we want to test? Use composer to require testing framework
  86. 86. @danaluther Update compose with composer composer: image: composer:latest command: ['bash','-c',"sleep infinity"] volumes: - ./src:/var/ www/html 08_LEMP
  87. 87. @danaluther Deploy stack updates > docker stack deploy -c docker-compose.yml hod 08_LEMP
  88. 88. @danaluther Deploy stack updates > docker stack deploy -c docker-compose.yml hod 08_LEMP
  89. 89. @danaluther Initialize composer > docker exec -it $(docker ps -lq -f name=hod_composer) bash 08_LEMP
  90. 90. @danaluther Initialize composer > docker exec -it $(docker ps -lq -f name=hod_composer) bash 08_LEMP
  91. 91. SIDEBAR: @danaluther > docker ps -lq -f name=stack_service The command to rule them all … > docker exec -it 36fce0da4a8f bash > docker exec -it $(docker ps -lq -f name=hod_php) bash
  92. 92. SIDEBAR: @danaluther > docker ps -lq -f name=stack_service The command to rule them all … > docker exec -it 36fce0da4a8f bash > docker exec -it $(docker ps -lq -f name=hod_php) bash
  93. 93. @danaluther Initialize composer > docker exec -it $(docker ps -lq -f name=hod_composer) bash 08_LEMP
  94. 94. SIDEBAR: @danaluther Don’t want to mess with the composer install today? Use the “with_vendor” branch alternates I got you! 09_LEMP_with_vendor 10_LEMP_with_vendor
  95. 95. @danaluther Require codeception bash-5.0# composer require codeception/codeception --dev 08_LEMP
  96. 96. @danaluther Alternately … composer install bash-5.0# composer install 09_LEMP
  97. 97. @danaluther Confirm codeception installation 09_LEMP
  98. 98. @danaluther Access via a php container > docker exec -it $(docker ps -lq -f name=hod_php) bash 09_LEMP
  99. 99. @danaluther Verify that you can run unit tests 10_LEMP
  100. 100. @danaluther (What did we just run?) require '/var/ www/html/DemoQuickCalculator.php'; class testSampleTest extends CodeceptionTestUnit { /** * @var UnitTester */ protected $tester; // tests public function testBasicMath() { $this ->assertEquals(4, DemoQuickCalculator ::alwaysEquals4()); } }
  101. 101. @danaluther (What did we just run?) /** * Class DemoQuickCalculator * Quick and dirty class to show that we can run unit tests */ class DemoQuickCalculator { /** * @return int */ public static function alwaysEquals4(): int { return 2+2; } }
  102. 102. @danaluther Make it fail … /** * Class DemoQuickCalculator * Quick and dirty class to show that we can run unit tests */ class DemoQuickCalculator { /** * @return int */ public static function alwaysEquals4(): int { return 2+3; } }
  103. 103. @danaluther Run the test again … 10_LEMP
  104. 104. @danaluther Quick Break - Stretch!
  105. 105. @danaluther Enable headless browsers for testing
  106. 106. @danaluther Enable headless browsers for testing Update docker-compose.yml with Chrome and Firefox images
  107. 107. @danaluther Enable headless browsers for testing Update docker-compose.yml with Chrome and Firefox images Default to 0 containers - scale the service up/down as needed
  108. 108. @danaluther Enable headless browsers for testing Update docker-compose.yml with Chrome and Firefox images Default to 0 containers - scale the service up/down as needed Take advantage of YAML anchors in the .yml to keep the compose file dry
  109. 109. SIDEBAR: @danaluther What are YAML anchors? Additional Resources https://nickjanetakis.com/blog/docker-tip-82-using-yaml-anchors-and-x-properties-in-docker-compose https://confluence.atlassian.com/bitbucket/yaml-anchors-960154027.html Anchor & Alias * Override <<:
  110. 110. @danaluther Setting up x-defaults x-defaults: network: &network networks: - net selenium-services: &selenium-svc environment: # Required to avoid container startup hanging sometimes in # some environments JAVA_OPTS: -Djava.security.egd=file:/dev/./urandom ports: - "4444:4444" deploy: replicas: 0 restart_policy: condition: on-failure <<: *network 10_LEMP
  111. 111. SIDEBAR: @danaluther The deploy block selenium-services: &selenium-svc … deploy: replicas: 0 restart_policy: condition: on-failure
  112. 112. @danaluther Implementing x-default network php: # Custom PHP Image - see /images/Readme.md image: dhluther/php:7.4-debug volumes: - ./src:/var/ www/html <<: *network … networks: net: 10_LEMP
  113. 113. @danaluther Setting up Chrome and Firefox #Used for Acceptance Tests for Firefox firefox: image: selenium/standalone-firefox-debug:2.53.0 <<: *selenium-svc #Used for Acceptance Tests for Chrome chrome: image: selenium/standalone-chrome-debug <<: *selenium-svc ports: - "4443:4444" 10_LEMP
  114. 114. @danaluther Deploy and Scale services 10_LEMP
  115. 115. @danaluther What if we forget to scale up chrome? 10_LEMP
  116. 116. @danaluther So how do we swap out php versions?
  117. 117. @danaluther Build the 7.3-fpm image > docker image build -f Dockerfile-php-mysql -t dhluther/php:7.3-fpm-mysql-c --target=customized . --build-arg PHP_TARGET=7.3-fpm 10_LEMP
  118. 118. @danaluther Build the 7.3-fpm image > docker image build -f Dockerfile-php-mysql -t dhluther/php:7.3-fpm-mysql-c --target=customized . --build-arg PHP_TARGET=7.3-fpm 10_LEMP > docker image build -f Dockerfile-php-mysql -t dhluther/php:7.3-debug --target=debug . --build-arg PHP_TARGET=7.3-fpm
  119. 119. @danaluther Build the 7.3-fpm image 10_LEMP
  120. 120. @danaluther Update the service > docker service update --image=dhluther/php:7.3-fpm-mysql-c hod_php
  121. 121. @danaluther Update the service > docker service update --image=dhluther/php:7.3-fpm-mysql-c hod_php
  122. 122. POPQUIZ! @danaluther Does anyone remember how to get into the container to run our unit test?
  123. 123. POPQUIZ! @danaluther Does anyone remember how to get into the container to run our unit test? > docker exec -it $(docker ps -lq -f name=hod_php) bash
  124. 124. @danaluther Run our unit test
  125. 125. @danaluther
  126. 126. @danaluther Verify the MySQL page
  127. 127. @danaluther Roll back the service > docker service rollback hod_php
  128. 128. SIDEBAR: @danaluther Updates and rollbacks happen sequentially when affecting a service with more than one container running.
  129. 129. SIDEBAR: @danaluther Update a service…
  130. 130. SIDEBAR: @danaluther Rollback a service…
  131. 131. @danaluther But what about additional services?
  132. 132. @danaluther Add new services to our stack phpMyAdmin — https://www.phpmyadmin.net/ Redis — https://redis.io/
  133. 133. @danaluther Define the phpMyAdmin service phpmyadmin: image: phpmyadmin/phpmyadmin environment: - PMA_ARBITRARY=1 deploy: replicas: 1 restart_policy: condition: on-failure ports: - 8081:80 <<: *network volumes: - /sessions 11_LEMP
  134. 134. @danaluther Deploy stack updates > docker stack deploy -c docker-compose.yml hod 11_LEMP
  135. 135. @danaluther localhost:8081
  136. 136. @danaluther localhost:8081
  137. 137. @danaluther Define the redis service redis: image: redis:latest volumes: - ./data_redis:/data deploy: placement: constraints: [node.role == manager] <<: *network 12_LEMP
  138. 138. @danaluther Deploy stack updates > docker stack deploy -c docker-compose.yml hod 12_LEMP
  139. 139. @danaluther Verify redis is running
  140. 140. @danaluther Can I use a GUI to help me?
  141. 141. @danalutherhttps://portainer.io
  142. 142. @danaluther Deploy the portainer stack > docker stack deploy -c docker-compose-portainer.yml hod_port 12_LEMP
  143. 143. @danaluther
  144. 144. @danaluther
  145. 145. @danaluther
  146. 146. @danaluther
  147. 147. @danaluther
  148. 148. @danaluther
  149. 149. @danaluther
  150. 150. @danaluther Shut it down! > docker stack rm hod > docker swarm leave --force > docker stack rm hod_port
  151. 151. @danaluther Questions?? 🤔 ? ? ? ? https://www.linkedin.com/in/danaluther dluther@envisageinternational.com https://git.io/JvUy5 https://joind.in/talk/d1bc3

×