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

LAMP in Containers

LAMP in Containers

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

Terrence Ryan

April 06, 2017
Tweet

More Decks by Terrence Ryan

Other Decks in Technology

Transcript

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

    View Slide

  2. ‹#›
    @tpryan
    Who are you?

    View Slide

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

    View Slide

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

    View Slide

  5. ‹#›
    @tpryan

    View Slide

  6. ‹#›
    @tpryan

    View Slide

  7. ‹#›
    @tpryan
    Demo: LAMP Version

    View Slide

  8. ‹#›
    @tpryan
    02 LAMP Version

    View Slide

  9. ‹#›
    @tpryan
    DB
    API
    UI
    LAMP

    View Slide

  10. ‹#›
    @tpryan
    Process
    • Create a server
    • Linux
    • Apache
    • PHP
    • MySQL
    • Get starting schema and content on it
    • Initialize system

    View Slide

  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

    View Slide

  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')

    View Slide

  13. ‹#›
    @tpryan
    Details
    Time to build ~ 2:30
    Time to update ~ :10
    Lines of config code 63
    Monthly Cost of Solution ~$4.28

    View Slide

  14. ‹#›
    @tpryan
    02 3 Tier Version

    View Slide

  15. ‹#›
    @tpryan
    DB
    API
    UI

    View Slide

  16. ‹#›
    @tpryan
    DB
    UI
    API

    View Slide

  17. ‹#›
    @tpryan
    03 Containerized

    View Slide

  18. ‹#›
    @tpryan
    03.1 Docker

    View Slide

  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

    View Slide

  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

    View Slide

  21. ‹#›
    @tpryan
    Code Changes
    Change frontend PUT requests to POST to deal with CORS issues.
    DB
    UI
    API

    View Slide

  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

    View Slide

  23. ‹#›
    @tpryan
    But secretly the API didn’t really care.
    if ($post_vars['id'] == 0){
    // INSERT SQL..
    } else {
    // UPDATE SQL...
    }
    API

    View Slide

  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
    });

    View Slide

  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

    View Slide

  26. ‹#›
    @tpryan
    03.2 Kubernetes

    View Slide

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

    View Slide

  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/

    View Slide

  29. ‹#›
    @tpryan
    # UI
    FROM httpd:2.4
    COPY ui /usr/local/apache2/htdocs/ui
    COPY static /usr/local/apache2/htdocs/static

    View Slide

  30. ‹#›
    @tpryan
    Docker

    View Slide

  31. ‹#›
    @tpryan
    Docker

    View Slide

  32. ‹#›
    @tpryan
    Docker

    View Slide

  33. ‹#›
    @tpryan
    Docker Docker

    View Slide

  34. ‹#›
    @tpryan
    Docker
    Docker

    View Slide

  35. ‹#›
    @tpryan
    Docker Docker

    View Slide

  36. ‹#›
    @tpryan
    Docker

    View Slide

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

    View Slide

  38. ‹#›
    @tpryan
    4 3 1

    View Slide

  39. ‹#›
    @tpryan
    Kubernetes
    • Container Orchestration System
    • Open Source
    • Started by Google
    • Contributed to by others

    View Slide

  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

    View Slide

  41. ‹#›
    @tpryan
    Create a Cluster
    # Request Cluster
    gcloud container clusters create $(CLUSTER) --num-nodes 2 \
    --disk-size=200 —machine-type="g1-small"

    View Slide

  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

    View Slide

  43. ‹#›
    @tpryan
    Running containers
    Pod Pod Pod Pod
    Replica Set
    Deployment

    View Slide

  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

    View Slide

  45. ‹#›
    @tpryan
    Create a Deployment
    # Create deployment
    kubectl create -f deployment.yaml

    View Slide

  46. ‹#›
    @tpryan
    Containers as Pets
    Pod
    Stateful Set
    Persistent
    Volume
    Claim

    View Slide

  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

    View Slide

  48. ‹#›
    @tpryan
    Exposing containers
    Pod Pod Pod Pod
    Service

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  52. ‹#›
    @tpryan
    Demo: Kubernetes Version

    View Slide

  53. ‹#›
    @tpryan
    Details
    Time to build ~ 4:30
    Time to update ~ :24
    Lines of config code 266
    Monthly Cost of Solution* ~$43.63

    View Slide

  54. ‹#›
    @tpryan
    Is this the right way?

    View Slide

  55. ‹#›
    @tpryan
    04 Cloud Version

    View Slide

  56. ‹#›
    @tpryan
    DB
    API
    UI
    Managed SQL
    File Storage
    Leave on Kubernetes
    Switch to App Engine flexible

    View Slide

  57. ‹#›
    @tpryan
    Details
    Time to build ~ 8:00
    Time to update ~ 5:00
    Lines of config code 66
    Monthly Cost of Solution ~$47.83

    View Slide

  58. ‹#›
    @tpryan
    05 Conclusions
    Bring it home

    View Slide

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

    View Slide

  60. ‹#›
    @tpryan
    LAMP

    =
    L+A+M+P

    View Slide

  61. ‹#›
    @tpryan
    Technology
    Shift

    View Slide

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

    View Slide