Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

‹#› @tpryan Who are you?

Slide 3

Slide 3 text

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

Slide 4

Slide 4 text

‹#› @tpryan I have an app…

Slide 5

Slide 5 text

‹#› @tpryan

Slide 6

Slide 6 text

‹#› @tpryan

Slide 7

Slide 7 text

‹#› @tpryan Demo: LAMP Version

Slide 8

Slide 8 text

‹#› @tpryan 02 LAMP Version

Slide 9

Slide 9 text

‹#› @tpryan DB API UI LAMP

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

‹#› @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

Slide 12

Slide 12 text

‹#› @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')

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

‹#› @tpryan 02 3 Tier Version

Slide 15

Slide 15 text

‹#› @tpryan DB API UI

Slide 16

Slide 16 text

‹#› @tpryan DB UI API

Slide 17

Slide 17 text

‹#› @tpryan 03 Containerized

Slide 18

Slide 18 text

‹#› @tpryan 03.1 Docker

Slide 19

Slide 19 text

‹#› @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

Slide 20

Slide 20 text

‹#› @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

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

‹#› @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

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

‹#› @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 });

Slide 25

Slide 25 text

‹#› @tpryan Details Time to build ~ :08 (+2:30) Time to update ~ :21 + (:10) Lines of config code 95 Monthly Cost of Solution* ~$4.28

Slide 26

Slide 26 text

‹#› @tpryan 03.2 Kubernetes

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

‹#› @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/

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

‹#› @tpryan Docker

Slide 31

Slide 31 text

‹#› @tpryan Docker

Slide 32

Slide 32 text

‹#› @tpryan Docker

Slide 33

Slide 33 text

‹#› @tpryan Docker Docker

Slide 34

Slide 34 text

‹#› @tpryan Docker Docker

Slide 35

Slide 35 text

‹#› @tpryan Docker Docker

Slide 36

Slide 36 text

‹#› @tpryan Docker

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

‹#› @tpryan 4 3 1

Slide 39

Slide 39 text

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

Slide 40

Slide 40 text

‹#› @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

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

‹#› @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

Slide 43

Slide 43 text

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

Slide 44

Slide 44 text

‹#› @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

Slide 45

Slide 45 text

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

Slide 46

Slide 46 text

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

Slide 47

Slide 47 text

‹#› @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

Slide 48

Slide 48 text

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

Slide 49

Slide 49 text

‹#› @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

Slide 50

Slide 50 text

‹#› @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

Slide 51

Slide 51 text

‹#› @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

Slide 52

Slide 52 text

‹#› @tpryan Demo: Kubernetes Version

Slide 53

Slide 53 text

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

Slide 54

Slide 54 text

‹#› @tpryan Is this the right way?

Slide 55

Slide 55 text

‹#› @tpryan 04 Cloud Version

Slide 56

Slide 56 text

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

Slide 57

Slide 57 text

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

Slide 58

Slide 58 text

‹#› @tpryan 05 Conclusions Bring it home

Slide 59

Slide 59 text

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

Slide 60

Slide 60 text

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

Slide 61

Slide 61 text

‹#› @tpryan Technology Shift

Slide 62

Slide 62 text

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