LAMP in Containers

LAMP in Containers

An exploration of converting a LAMP app to a multi tier container app.

6c18ceafef161be26ae441469b29c475?s=128

Terrence Ryan

April 06, 2017
Tweet

Transcript

  1. ‹#› @tpryan Terry Ryan Developer Advocate LAMP In Containers

  2. ‹#› @tpryan Who are you?

  3. ‹#› @tpryan 01 Introduction What Am I Trying to Do?

  4. ‹#› @tpryan I have an app…

  5. ‹#› @tpryan

  6. ‹#› @tpryan

  7. ‹#› @tpryan Demo: LAMP Version

  8. ‹#› @tpryan 02 LAMP Version

  9. ‹#› @tpryan DB API UI LAMP

  10. ‹#› @tpryan Process • Create a server • Linux •

    Apache • PHP • MySQL • Get starting schema and content on it • Initialize system
  11. ‹#› @tpryan Create a Server # Request Machine gcloud compute

    instances create $(MYSQL_HOSTNAME) --zone $(ZONE) \ --machine-type "f1-micro" --image-family="debian-8" \ --image-project="debian-cloud" \ --tags "http-server","https-server" # Install Apache + PHP apt-get update -y apt-get install apache2 php5 curl php5-curl -y # Install MySQL and PHP libratries DEBIAN_FRONTEND=noninteractive \ apt-get -y install mysql-server mysql-client php5-mysqlnd php-pear -y /etc/init.d/apache2 restart
  12. ‹#› @tpryan Create a Server # Security routines DELETE FROM

    mysql.user WHERE User='root' AND Host = '$(MYSQL_HOSTNAME)'; SET PASSWORD FOR 'root'@'localhost' = '$(MYSQL_ROOTHASH)'; SET PASSWORD FOR 'root'@'127.0.0.1' = '$(MYSQL_ROOTHASH)'; SET PASSWORD FOR 'root'@'::1' = '$(MYSQL_ROOTHASH)'; FLUSH PRIVILEGES; mysql_secure_installation $(MYSQL_ROOTHASH) = SELECT PASSWORD('SuperSecureIPromise')
  13. ‹#› @tpryan Details Time to build ~ 2:30 Time to

    update ~ :10 Lines of config code 63 Monthly Cost of Solution ~$4.28
  14. ‹#› @tpryan 02 3 Tier Version

  15. ‹#› @tpryan DB API UI

  16. ‹#› @tpryan DB UI API

  17. ‹#› @tpryan 03 Containerized

  18. ‹#› @tpryan 03.1 Docker

  19. ‹#› @tpryan Dockerfiles FROM mysql/mysql-server:5.6 ADD sql/load.sql /docker-entrypoint-initdb.d/load.sql EXPOSE 3306

    DB FROM httpd:2.4 COPY ui /usr/local/apache2/htdocs/ui COPY static /usr/local/apache2/htdocs/static UI FROM php:7.0-apache RUN apt-get update && apt-get install -y php5-mysqlnd RUN docker-php-ext-install mysqli RUN a2enmod rewrite && a2enmod headers && service apache2 restart COPY app/ /var/www/html/ API
  20. ‹#› @tpryan docker run --name=3tier_frontend -d -p 8080:80 3tier_frontend docker

    run --name=3tier_api --link 3tier_db:mysql -d -p 80:80 3tier_api Startup scripts docker run --name=3tier_db -d -p 3306:3306 3tier_db DB UI API
  21. ‹#› @tpryan Code Changes Change frontend PUT requests to POST

    to deal with CORS issues. DB UI API
  22. ‹#› @tpryan Original UI var url = this.protocol + this.host

    + this.uri_location_list; var type = "POST"; if (location.id != 0){ url += location.id; type = "PUT"; } $.ajax({ url: url, type: type, data: location, success: successHandler, error: errorHandler }); UI
  23. ‹#› @tpryan But secretly the API didn’t really care. if

    ($post_vars['id'] == 0){ // INSERT SQL.. } else { // UPDATE SQL... } API
  24. ‹#› @tpryan So now this var url = this.protocol +

    this.host + this.uri_location_list; var type = "POST"; if (location.id != 0){ url += location.id; type = "PUT"; } $.ajax({ url: url, type: type, data: location, success: successHandler, error: errorHandler }); UI var url = this.protocol + this.host + this.uri_location_list; var type = "POST"; if (location.id != 0){ url += location.id; type = "PUT"; } $.ajax({ url: url, type: type, data: location, success: successHandler, error: errorHandler });
  25. ‹#› @tpryan Details Time to build ~ :08 (+2:30) Time

    to update ~ :21 + (:10) Lines of config code 95 Monthly Cost of Solution* ~$4.28
  26. ‹#› @tpryan 03.2 Kubernetes

  27. ‹#› @tpryan # DB FROM mysql/mysql-server:5.6 ADD sql/load.sql /docker-entrypoint-initdb.d/load.sql EXPOSE

    3306
  28. ‹#› @tpryan # FRONTEND AND SERVICES FROM nginx-php-fpm COPY nginx.conf

    /etc/nginx/nginx.conf ADD www /var/www/ # API FROM php:7.0-apache RUN apt-get update && apt-get install -y php5-mysqlnd RUN docker-php-ext-install mysqli RUN a2enmod rewrite && a2enmod headers && service apache2 restart COPY app/ /var/www/html/
  29. ‹#› @tpryan # UI FROM httpd:2.4 COPY ui /usr/local/apache2/htdocs/ui COPY

    static /usr/local/apache2/htdocs/static
  30. ‹#› @tpryan Docker

  31. ‹#› @tpryan Docker

  32. ‹#› @tpryan Docker

  33. ‹#› @tpryan Docker Docker

  34. ‹#› @tpryan Docker Docker

  35. ‹#› @tpryan Docker Docker

  36. ‹#› @tpryan Docker

  37. ‹#› @tpryan That’s a lot to manage.

  38. ‹#› @tpryan 4 3 1

  39. ‹#› @tpryan Kubernetes • Container Orchestration System • Open Source

    • Started by Google • Contributed to by others
  40. ‹#› @tpryan Requirements • Kubernetes Cluster • Images hosted in

    repository • Multiple running containers for • API • UI • Single instance of • DB • Disk for • DB • Public IP and load balancers for • API • UI
  41. ‹#› @tpryan Create a Cluster # Request Cluster gcloud container

    clusters create $(CLUSTER) --num-nodes 2 \ --disk-size=200 —machine-type="g1-small"
  42. ‹#› @tpryan Build and host images # Build API image

    docker build -t gcr.io/projectname/locations-api "containers/api/." # Push API to repository gcloud docker push gcr.io/projectname/locations-api # Build UI image docker build -t gcr.io/projectname/locations-ui "containers/ui/." # Push UI to repository gcloud docker push gcr.io/projectname/locations-ui # Build DB image docker build -t gcr.io/projectname/locations-db "containers/db/." # Push API to repository gcloud docker push gcr.io/projectname/locations-db
  43. ‹#› @tpryan Running containers Pod Pod Pod Pod Replica Set

    Deployment
  44. ‹#› @tpryan Deployment apiVersion: extensions/v1beta1 kind: Deployment metadata: name: frontend-deployment

    spec: replicas: 4 strategy: type: RollingUpdate template: metadata: labels: layer: ui spec: containers: - name: "frontend" image: "gcr.io/lamp-in-containers/locations-frontend" ports: - name: "http" containerPort: 80 protocol: TCP Pod Replica Set Deployment
  45. ‹#› @tpryan Create a Deployment # Create deployment kubectl create

    -f deployment.yaml
  46. ‹#› @tpryan Containers as Pets Pod Stateful Set Persistent Volume

    Claim
  47. ‹#› @tpryan Stateful Set apiVersion: apps/v1beta1 kind: StatefulSet metadata: name:

    db-set spec: serviceName: "mysql" replicas: 1 template: metadata: labels: layer: db spec: terminationGracePeriodSeconds: 0 containers: - name: db image: "gcr.io/lamp-in-containers/locations-db" ports: - containerPort: 3306 name: mysql volumeMounts: - name: mysql-pvc mountPath: /var/lib/mysql volumeClaimTemplates: - metadata: name: mysql-pvc annotations: volume.alpha.kubernetes.io/storage-class: anything spec: accessModes: [ "ReadWriteOnce" ] resources: requests: storage: 1Gi Pod Persistent Volume Claim Stateful Set
  48. ‹#› @tpryan Exposing containers Pod Pod Pod Pod Service

  49. ‹#› @tpryan Deployment apiVersion: extensions/v1beta1 kind: Deployment metadata: name: frontend-deployment

    spec: replicas: 4 strategy: type: RollingUpdate template: metadata: labels: layer: ui spec: containers: - name: "frontend" image: "gcr.io/lamp-in-containers/locations-frontend" ports: - name: "http" containerPort: 80 protocol: TCP Pod Label
  50. ‹#› @tpryan Service apiVersion: v1 kind: Service metadata: labels: name:

    frontend name: frontend spec: type: LoadBalancer ports: - port: 80 targetPort: 80 protocol: TCP selector: layer: ui Selector
  51. ‹#› @tpryan ui Pod ui deployment ui Pod ui Pod

    ui Pod ui service (public) api Pod api deployment api service (public) api Pod api Pod db statefulset db service (private) db Pod
  52. ‹#› @tpryan Demo: Kubernetes Version

  53. ‹#› @tpryan Details Time to build ~ 4:30 Time to

    update ~ :24 Lines of config code 266 Monthly Cost of Solution* ~$43.63
  54. ‹#› @tpryan Is this the right way?

  55. ‹#› @tpryan 04 Cloud Version

  56. ‹#› @tpryan DB API UI Managed SQL File Storage Leave

    on Kubernetes Switch to App Engine flexible
  57. ‹#› @tpryan Details Time to build ~ 8:00 Time to

    update ~ 5:00 Lines of config code 66 Monthly Cost of Solution ~$47.83
  58. ‹#› @tpryan 05 Conclusions Bring it home

  59. ‹#› @tpryan All in one boxes are a liability

  60. ‹#› @tpryan LAMP
 = L+A+M+P

  61. ‹#› @tpryan Technology Shift

  62. ‹#› @tpryan Thank You terrenceryan.com @tpryan This preso: http://bit.ly/tpryan-chaos