├── .gitignore ├── 00-setup.md ├── 01-pods-deployments-services.md ├── 02-secrets-environment-variables.md ├── 03-volumes.md ├── 04-dockerize-rails-for-kubernetes.md ├── 05-blue-green.md ├── README.md ├── code-snippets ├── Dockerfile ├── database.yml ├── hit_counter.rb ├── routes.rb └── slash_controller.rb ├── graffles ├── blue-green.graffle └── kubernetes.graffle └── k8s-manifests ├── 01-db-storage-class.yaml ├── 02-db-volume-claim.yaml ├── 03-db-secret.yaml ├── 04-db-deployment.yaml ├── 05-db-service.yaml └── 06-rails-app.yaml /.gitignore: -------------------------------------------------------------------------------- 1 | nothing-to-see-in-here 2 | -------------------------------------------------------------------------------- /00-setup.md: -------------------------------------------------------------------------------- 1 | # Signup for the eventbrite 2 | 3 | open http://ey.io/kubey 4 | 5 | # Check your email 6 | 7 | # Create an Account 8 | 9 | # Copy/Paste the SSH command into a terminal 10 | 11 | # Run `k cluster-info` 12 | 13 | All Set! -------------------------------------------------------------------------------- /01-pods-deployments-services.md: -------------------------------------------------------------------------------- 1 | # Pods, Deployments, Services 2 | 3 | Deploy a rails app to kubernetes using a Deployment. Interact with the created Pods. Scale the Deployment. Expose the app to the internet with a Service. 4 | 5 | # Steps 6 | 7 | ## Deployment 8 | 9 | Create a deployment: 10 | 11 | k run k8sapp --image=engineyard/k8sapp --port 5000 --labels="app=k8sapp" 12 | 13 | See it running 14 | 15 | The Pods where the app is actually running: 16 | 17 | k get pods -o wide 18 | 19 | NAME READY STATUS RESTARTS AGE IP NODE 20 | k8sapp-1336000273-0mwsc 0/1 ContainerCreating 0 7s ip-172-20-1-239.us-west-2.compute.internal 21 | 22 | The Deployment which manages the replica sets: 23 | 24 | k get deployments 25 | 26 | NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE 27 | k8sapp 1 1 1 0 55s 28 | 29 | The replica sets: 30 | 31 | k get replicasets 32 | 33 | NAME DESIRED CURRENT READY AGE 34 | k8sapp-1336000273 1 1 0 1m 35 | 36 | When everything is up and running, pod will have an IP: 37 | 38 | NAME READY STATUS RESTARTS AGE IP NODE 39 | k8sapp-1336000273-0mwsc 1/1 Running 0 3m 10.200.1.5 ip-172-20-1-239.us-west-2.compute.internal 40 | 41 | We can exec into the running container: 42 | 43 | k exec -it k8sapp-1336000273-0mwsc bash 44 | 45 | wget -qO- http://localhost:5000 46 | 47 | Or start a new container just for interacting: 48 | 49 | k run -it bashbox --image=ruby:2.3 --rm -- bash 50 | 51 | And using the IP of the running Pod, we see that the app is exposed to other Pods in kubernetes 52 | 53 | wget -qO- http://10.200.1.5:5000 54 | seq 5 | xargs -I{} wget -qO- http://10.200.1.5:5000 55 | 56 | But we're still not exposed outside the cluster. And our IP will change if our Pod is re-created (due to deployment, scaling, etc..) 57 | 58 | If we kill the pod, the replica set will re-create it 59 | 60 | ## Service 61 | 62 | Create a clusterIP service 63 | 64 | k create service clusterip k8sapp --tcp=80:5000 65 | 66 | k get services -o wide 67 | 68 | NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR 69 | k8sapp 10.254.221.20 80/TCP 6s app=k8sapp 70 | kubernetes 10.254.0.1 443/TCP 4h 71 | 72 | List matching pods (by label) 73 | 74 | k get pods -l app=k8sapp 75 | NAME READY STATUS RESTARTS AGE 76 | k8sapp-3607609085-653nx 1/1 Running 0 3m 77 | 78 | Now back to a container just for interacting: 79 | 80 | k run -it bashbox --image=ruby:2.3 --rm -- bash 81 | 82 | We can see that the cluster ip is usable 83 | 84 | wget -qO- http://10.254.221.20 85 | 86 | And kubeDNS can also get us to the services 87 | 88 | wget -qO- http://k8sapp 89 | 90 | And we even have some environment variables 91 | 92 | root@bashbox-2310052996-q6hdc:/# env | grep K8SAPP 93 | K8SAPP_PORT_80_TCP=tcp://10.254.221.20:80 94 | K8SAPP_SERVICE_PORT=80 95 | K8SAPP_SERVICE_PORT_80_5000=80 96 | K8SAPP_PORT=tcp://10.254.221.20:80 97 | K8SAPP_PORT_80_TCP_PORT=80 98 | K8SAPP_PORT_80_TCP_PROTO=tcp 99 | K8SAPP_SERVICE_HOST=10.254.221.20 100 | K8SAPP_PORT_80_TCP_ADDR=10.254.221.20 101 | 102 | ## Ingress 103 | 104 | We're still not exposed outside the cluster! Let's fix that. 105 | 106 | We could use an ELB. We can provision one like so: 107 | 108 | k expose deployment k8sapp --type=LoadBalancer --name=k8sappelb --port=80 --target-port=5000 109 | 110 | Or we can use the nginx-ingress, which already has an ELB attached, and will allow us to share that ELB across multiple apps. 111 | 112 | k get services/nginx-ingress -n kube-system -o wide 113 | 114 | NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR 115 | nginx-ingress 10.254.178.91 a192b4016291211e78cd7023e9bf8dfa-111615484.us-east-1.elb.amazonaws.com 80:31659/TCP 4h app=nginx-ingress 116 | 117 | (FYI `get services --all-namespaces` to explore things in other namespaces) 118 | 119 | That ELB that's already setup, also has a useful CNAME (thanks Engine Yard). 120 | 121 | nslookup *.${ENV_NAME}.my.ey.io 122 | 123 | ... 124 | *.bukeybasha2.my.ey.io canonical name = a192b4016291211e78cd7023e9bf8dfa-111615484.us-east-1.elb.amazonaws.com. 125 | Name: a192b4016291211e78cd7023e9bf8dfa-111615484.us-east-1.elb.amazonaws.com 126 | Address: 34.197.151.80 127 | ... 128 | 129 | So let's create an ingress (beware of): 130 | 131 | echo "apiVersion: extensions/v1beta1 132 | kind: Ingress 133 | metadata: 134 | name: k8sapp 135 | spec: 136 | rules: 137 | #CAN use underscores but NO dashes 138 | - host: k8sapp.${ENV_NAME}.my.ey.io 139 | http: 140 | paths: 141 | - backend: 142 | serviceName: k8sapp 143 | servicePort: 80" | kubectl create -f - 144 | 145 | See that the ingress was created 146 | 147 | k get ingress 148 | 149 | Try it! 150 | 151 | curl k8sapp.${ENV_NAME}.my.ey.io 152 | 153 | Or open in a browser 154 | 155 | echo http://k8sapp.${ENV_NAME}.my.ey.io 156 | 157 | (copy/paste into a web browser) 158 | 159 | We are finally publicly exposed! 160 | 161 | Our load balancer should by provisioned by now too: 162 | 163 | k get services -o wide 164 | 165 | NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR 166 | k8sapp 10.254.221.20 80/TCP 31m app=k8sapp 167 | k8sappelb 10.254.147.68 a69c4fa4d252711e7b50a02a1fcd79f8-1821649505.us-west-2.elb.amazonaws.com 80:32592/TCP 21m app=k8sapp 168 | kubernetes 10.254.0.1 443/TCP 13h 169 | 170 | We are also exposed via ELB: 171 | 172 | curl a69c4fa4d252711e7b50a02a1fcd79f8-1821649505.us-west-2.elb.amazonaws.com 173 | 174 | ## Selectors & Labels 175 | 176 | Scale up (and expose some more problems with our app as-configured at the moment). 177 | 178 | k scale deployments/k8sapp --replicas=5 179 | 180 | Notice we don't have a working hit counter anymore (Hint: it wasn't working to begin with) 181 | 182 | seq 9 | xargs -I{} curl k8sapp.${ENV_NAME}.my.ey.io 183 | 184 | {"Hit Count":8}{"Hit Count":7}{"Hit Count":18}{"Hit Count":7}{"Hit Count":8}{"Hit Count":9}{"Hit Count":9}{"Hit Count":19}{"Hit Count":9} 185 | 186 | ... Still using sqlite and Rails env development. 187 | 188 | Now's a good time for a little sidetrack into selectors and labels 189 | 190 | k get pods 191 | 192 | k8sapp-3607609085-653nx 1/1 Running 0 25m 193 | k8sapp-3607609085-97f40 1/1 Running 0 11m 194 | k8sapp-3607609085-ddf9q 1/1 Running 0 11m 195 | k8sapp-3607609085-qjmhp 1/1 Running 0 11m 196 | k8sapp-3607609085-v05gz 1/1 Running 0 11m 197 | 198 | k edit pods/k8sapp-3607609085-ddf9q -o yaml 199 | 200 | Let's add the label `foo=bar`. (`vi` hint, arrow down to the `app: k8sapp` line, type `Y` to copy the line, `P` to paste it, `i` to begin editing it, `esc :wq` when you are done) 201 | 202 | labels: 203 | app: k8sapp 204 | pod-template-hash: "3607609085" 205 | 206 | becomes: 207 | 208 | labels: 209 | app: k8sapp 210 | foo: bar 211 | pod-template-hash: "3607609085" 212 | 213 | And let's do the same with the service: 214 | 215 | k edit services/k8sapp 216 | 217 | selector: 218 | app: k8sapp 219 | 220 | becomes 221 | 222 | selector: 223 | foo: bar 224 | 225 | Now our service is only hitting that 1 pod 226 | 227 | seq 9 | xargs -I{} curl k8sapp.${ENV_NAME}.my.ey.io 228 | 229 | {"Hit Count":10}{"Hit Count":11}{"Hit Count":12}{"Hit Count":13}{"Hit Count":14}{"Hit Count":15}{"Hit Count":16}{"Hit Count":17}{"Hit Count":18} 230 | 231 | Undo our little hacks before the next section 232 | -------------------------------------------------------------------------------- /02-secrets-environment-variables.md: -------------------------------------------------------------------------------- 1 | # Secrets and Environment Variables 2 | 3 | Set environment variable `RAILS_ENV` to production on our Rails app using `env` config. 4 | Set environment variable `SECRET_KEY_BASE` using a kubernetes secret. 5 | Connect to an externally configured RDS database connecting a pre-configured secret to `DATABASE_URL`. 6 | 7 | # Steps 8 | 9 | So far we've been using sqlite. If we kill the running pod, and let the deployment recreate it, the hit counter will start over back where it was when we built the docker image. 10 | 11 | $ seq 5 | xargs -I{} curl ae036ae591e7611e782cc0add41e3562-1667221753.us-east-1.elb.amazonaws.com 12 | {"Hit Count":32}{"Hit Count":33}{"Hit Count":34}{"Hit Count":35}{"Hit Count":36} 13 | 14 | $ k get pods 15 | NAME READY STATUS RESTARTS AGE 16 | k8sapp-2127871177-pzjld 1/1 Running 0 55s 17 | 18 | $ k delete pods/k8sapp-2127871177-pzjld 19 | pod "k8sapp-2127871177-pzjld" deleted 20 | 21 | $ k get pods 22 | NAME READY STATUS RESTARTS AGE 23 | k8sapp-2127871177-m0642 1/1 Running 0 2s 24 | k8sapp-2127871177-pzjld 1/1 Terminating 0 1m 25 | 26 | $ seq 5 | xargs -I{} curl ae036ae591e7611e782cc0add41e3562-1667221753.us-east-1.elb.amazonaws.com 27 | {"Hit Count":6}{"Hit Count":7}{"Hit Count":8}{"Hit Count":9}{"Hit Count":10} 28 | 29 | We're also still running in development mode. 30 | 31 | $ k get pods 32 | NAME READY STATUS RESTARTS AGE 33 | k8sapp-2127871177-m0642 1/1 Running 0 7m 34 | 35 | $ k exec -it k8sapp-2127871177-m0642 bash 36 | root@k8sapp-2127871177-m0642:/app# bundle exec rails c 37 | Running via Spring preloader in process 46 38 | Loading development environment (Rails 5.0.2) 39 | irb(main):001:0> Rails.env 40 | => "development" 41 | 42 | ### environment variables 43 | 44 | The kubernetes `deployment` is responsible for ensuring N replicas of our `k8sapp` pod is running. So we can actually delete and re-create the deployment without downtime if set `--cascade=false`, this will ensure the pods are not deleted. We'll then re-create it with environment variables. 45 | 46 | k get deployments 47 | 48 | NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE 49 | k8sapp 1 1 1 1 10h 50 | 51 | k delete deployments/k8sapp --cascade=false 52 | 53 | deployment "k8sapp" deleted 54 | 55 | k get pods 56 | 57 | NAME READY STATUS RESTARTS AGE 58 | k8sapp-2127871177-m0642 1/1 Running 0 51m 59 | 60 | k run k8sapp --image=engineyard/k8sapp --port 5000 --env="RAILS_ENV=production" --labels="app=k8sapp" 61 | 62 | If we load the app in a browser now (via ELB hostname) we should see an error: 63 | 64 | open http://ae036ae591e7611e782cc0add41e3562-1667221753.us-east-1.elb.amazonaws.com/ 65 | 66 | Missing `secret_key_base` for 'production' environment, set this value in `config/secrets.yml` 67 | 68 | ### Other environment variables to consider setting 69 | 70 | Tell rails to serve static assest (since we haven't setup nginx or CDN to serve them) 71 | 72 | RAILS_SERVE_STATIC_FILES=true 73 | 74 | Tell rails to output all logs to STDOUT instead of log files (so we can use `k logs`) 75 | 76 | RAILS_LOG_TO_STDOUT=true 77 | 78 | ### secrets 79 | 80 | Create a SECRET_KEY_BASE secret: 81 | 82 | ruby -rsecurerandom -e "print SecureRandom.hex(100)" > skb 83 | kubectl create secret generic secret-key-base --from-file=skb 84 | rm skb 85 | 86 | Verify it: 87 | 88 | $ k get secrets 89 | NAME TYPE DATA AGE 90 | secret-key-base Opaque 1 5s 91 | 92 | Attach the secret to the deployment, by editing and replacing the deployment: 93 | 94 | k get deployments/k8sapp -o json | \ 95 | ruby -rjson -e "puts JSON.pretty_generate(JSON.load(STDIN.read).tap{|x| 96 | x['spec']['template']['spec']['containers'].first['env'] << 97 | {name: 'SECRET_KEY_BASE', valueFrom: {secretKeyRef: {name: 'secret-key-base', key: 'skb'}}}})" | \ 98 | k replace -f - 99 | 100 | k get pods 101 | NAME READY STATUS RESTARTS AGE 102 | k8sapp-254138870-vmjj1 1/1 Terminating 0 19s 103 | k8sapp-596859129-kp76n 1/1 Running 0 14s 104 | 105 | k exec -it k8sapp-596859129-kp76n -- bash 106 | env 107 | ... 108 | SECRET_KEY_BASE=yH3dBDn6YTate8FXSyhrntDwMCPitSpv0cLmqCtTF1M... 109 | ... 110 | 111 | Now try the app again: 112 | 113 | open http://ae036ae591e7611e782cc0add41e3562-1667221753.us-east-1.elb.amazonaws.com/ 114 | 115 | Get a 500 error, but we're in `RAILS_ENV=production` now so it's not so easily visible 116 | 117 | We can try: 118 | 119 | k logs k8sapp-596859129-kp76n 120 | 121 | But that only gives us STDOUT of the puma process (unless `RAILS_LOG_TO_STDOUT` is set) 122 | We can also just exec into the pod again and look at the logs: 123 | 124 | k exec -it k8sapp-596859129-kp76n -- bash 125 | tail -f log/production.log 126 | ... 127 | ActiveRecord::StatementInvalid (SQLite3::SQLException: no such table: hit_counters 128 | ... 129 | 130 | So the database doesn't exist because it's still sqlite and we didn't migrate. Let's switch it to postgres by populating `DATABASE_URL` 131 | 132 | In a coming-very-soon version of the Engine Yard CLI: `kubey`, you'll be able to provision RDS databases. In the meantime, you'll have to make use of the one that's already provided. 133 | 134 | `k get secrets` should show that there's a `exampledb` secret. We can look at it's contents with a little help from ruby. 135 | 136 | `k get secret/exampledb -o yaml` shows a YAML description of the secret with an obfuscated value for `database-url`. But it's only obfuscated with Base64, so to see it's contents: 137 | 138 | k get secret/exampledb -o yaml | ruby -ryaml -rbase64 -e "puts Base64.decode64(YAML.load(STDIN)['data']['database-url'])" 139 | 140 | So now let's attach that secret to our cluster as DATABASE_URL 141 | 142 | k get deployments/k8sapp -o json | \ 143 | ruby -rjson -e "puts JSON.pretty_generate(JSON.load(STDIN.read).tap{|x| 144 | x['spec']['template']['spec']['containers'].first['env'] << 145 | {name: 'DATABASE_URL', valueFrom: {secretKeyRef: {name: 'exampledb', key: 'database-url'}}}})" | \ 146 | k replace -f - 147 | 148 | And we need to migrate (I'm afraid the solution is rather "manual" at the moment) 149 | 150 | $ k get pods 151 | NAME READY STATUS RESTARTS AGE 152 | k8sapp-3909670473-7cpz9 1/1 Running 0 1m 153 | $ k exec -it k8sapp-3909670473-7cpz9 -- bash 154 | bundle exec rake db:migrate 155 | 156 | And now, finally, it's working, right? 157 | 158 | open http://ae036ae591e7611e782cc0add41e3562-1667221753.us-east-1.elb.amazonaws.com/ 159 | 160 | ## proxy / ui 161 | 162 | k proxy 163 | 164 | Is a useful little UI we can serve up. It kinda assumes you are running `kubectl` locally and not this weird bridge box setup. 165 | 166 | Workaround: 167 | 168 | k proxy --address='0.0.0.0' --disable-filter=true 169 | 170 | And to get the public hostname of our bridge box (output you can paste into a web browser) 171 | 172 | echo $(curl -s http://169.254.169.254/latest/meta-data/public-hostname):8001 173 | -------------------------------------------------------------------------------- /03-volumes.md: -------------------------------------------------------------------------------- 1 | # This tutorial covers 2 | 3 | - Running PostgreSQL as a container on kubernetes and connecting it to your app. 4 | 5 | # Prerequisites 6 | 7 | - A Dockerized Rails app, ready to run on kubernetes (see: [Basic Rails App Tutorial](../01-basic-rails-app)) 8 | 9 | # Step by Step 10 | 11 | ## 1. Storage Class 12 | 13 | k create -f ~/kubernetes-workshop/k8s-manifests/01-db-storage-class.yaml 14 | k get storageclasses 15 | k describe storageclass/pg-pv 16 | 17 | ## 2. Volume Claim 18 | 19 | k create -f ~/kubernetes-workshop/k8s-manifests/02-db-volume-claim.yaml 20 | k get pvc 21 | k describe pvc/pg-pv-claim 22 | 23 | ## 3. Secret 24 | 25 | erb -r base64 -r securerandom ~/kubernetes-workshop/k8s-manifests/03-db-secret.yaml | kubectl create -f - 26 | k get secret/pg-db-secret -o jsonpath="{.data.postgres-password}" | base64 --decode 27 | 28 | ## 4. Deployment 29 | 30 | k create -f ~/kubernetes-workshop/k8s-manifests/04-db-deployment.yaml 31 | 32 | Verify with: 33 | 34 | k get pods 35 | 36 | NAME READY STATUS RESTARTS AGE 37 | ... 38 | pg-for-pg-rails-732073437-tln3r 0/1 ContainerCreating 0 22s 39 | 40 | k exec -it pg-for-pg-rails-732073437-tln3r bash 41 | 42 | root@pg-for-pg-rails-732073437-tw4vq:/# mount | grep post 43 | /dev/xvdba on /var/lib/postgresql/data type ext4 (rw,relatime,data=ordered) 44 | 45 | ## 5. DB Service 46 | 47 | Create the service for the DB 48 | 49 | k create -f ~/kubernetes-workshop/k8s-manifests/05-db-service.yaml 50 | 51 | Output the DB password (you'll need it again): 52 | 53 | k get secrets/pg-db-secret -o yaml | ruby -ryaml -rbase64 -e "YAML.load(STDIN)['data'].each{|k,v| puts [k, Base64.decode64(v)]}" 54 | 55 | Go into a new container and connect to your running postgres (exposed via that service) 56 | 57 | k run debug -it --rm --image=postgres --restart=Never -- bin/bash 58 | $ psql -h pg-rails-service -U postgres 59 | 60 | or connect via already running container 61 | 62 | k exec -it pg-for-pg-rails-732073437-tln3r bash 63 | 64 | ## 6. Consume DB Service from a Rails App 65 | 66 | Adjust `database.yml` to read from `DB_HOST` and `DB_PASSWORD` environment variables: 67 | 68 | <% if ENV['DATABASE_URL'].blank? %> 69 | production: 70 | # DB Service/Deployment provided by k8s will use shared secret (and become admin on the DB) 71 | <<: *default 72 | host: <%= ENV["DB_HOST"] %> 73 | user: postgres 74 | password: <%= ENV["DB_PASSWORD"] %> 75 | database: myapp_prod 76 | <% end %> 77 | 78 | This manifest will make a new deployment using an app from an image that does this... 79 | 80 | k create -f ~/kubernetes-workshop/k8s-manifests/06-rails-app.yaml 81 | 82 | And we can add it to our ingress with a service: 83 | 84 | k create service clusterip pg-rails --tcp=80:5000 85 | 86 | And a ingress 87 | 88 | echo "apiVersion: extensions/v1beta1 89 | kind: Ingress 90 | metadata: 91 | name: pg-rails 92 | spec: 93 | rules: 94 | #CAN use underscores but NO dashes 95 | - host: pg-rails.${ENV_NAME}.my.ey.io 96 | http: 97 | paths: 98 | - backend: 99 | serviceName: pg-rails 100 | servicePort: 80" | kubectl create -f - 101 | 102 | Open in browser: 103 | 104 | echo pg-rails.${ENV_NAME}.my.ey.io 105 | 106 | Still need to `rake db:create` and `rake db:migrate` 107 | 108 | k exec -it pg-rails-2356453321-vw36l bash 109 | 110 | bundle exec rake db:create 111 | bundle exec rake db:migrate 112 | -------------------------------------------------------------------------------- /04-dockerize-rails-for-kubernetes.md: -------------------------------------------------------------------------------- 1 | # Dockerize a Rails App (for kubernetes) 2 | 3 | Create a new rails app (or use an existing one). 4 | Add a Dockerfile 5 | `docker build` and `docker push` 6 | `kubectl run` 7 | 8 | # Step by Step 9 | 10 | ## 1. `rails new` 11 | 12 | rails new myapp 13 | cd myapp 14 | 15 | We'll be using postgres as the database, so make sure they are in your Gemfile (`vi Gemfile`): 16 | 17 | vi Gemfile 18 | 19 | ... 20 | gem 'pg' 21 | 22 | bundle 23 | 24 | Now do something that would require a database, and respond on "/". 25 | Be creative, or copy from https://github.com/engineyard/k8sapp 26 | 27 | a model: 28 | 29 | bundle exec rails generate model HitCounter hits:integer 30 | cp ~/kubernetes-workshop/code-snippets/hit_counter.rb app/models/hit_counter.rb 31 | 32 | a controller: 33 | 34 | bundle exec rails generate controller Slash 35 | cp ~/kubernetes-workshop/code-snippets/slash_controller.rb app/controllers/slash_controller.rb 36 | 37 | a route: 38 | 39 | cp ~/kubernetes-workshop/code-snippets/routes.rb config/routes.rb 40 | 41 | If you've just copied verbatim up to this point, maybe do at least SOMEHTING custom by modifying the output, just be sure it's YOUR app that's being run and not one of the images generated by the tutorial authors. 42 | 43 | vi app/controllers/slash_controller.rb 44 | 45 | ... 46 | render json: {"Hit Count" => HitCounter.hits, "Owner" => "Leowen"} 47 | ... 48 | 49 | ## 1.5 Test run with puma (optional) 50 | 51 | You should be able to run your app locally 52 | 53 | bundle 54 | bundle exec rake db:migrate 55 | 56 | Output the URL to open in your web browser 57 | 58 | echo $(curl -s http://169.254.169.254/latest/meta-data/public-hostname):5000 59 | 60 | Start puma sever on port 5000 61 | 62 | bundle exec puma -p 5000 63 | 64 | If you were doing this on your local dev machine you'd pop open a browser and visit localhost:5000, 65 | but since you are doing this on the "bridge" box you'll need to point your browser at the amazon public hostname plus port 5000. 66 | 67 | ## 2. Dockerfile 68 | 69 | Our app will run inside a container, so we need a Dockerfile that defines how to setup it's OS-level dependencies and ends with what command to run (`bundle exec puma -p 5000`) 70 | 71 | vi Dockerfile 72 | 73 | Here's a starting point: 74 | 75 | #The base image, with ruby pre-installed 76 | #see: https://hub.docker.com/_/ruby/ 77 | FROM ruby:2.3 78 | 79 | # Install dependencies: 80 | # - build-essential: To ensure certain gems can be compiled 81 | # - nodejs: Compile assets 82 | # - libpq-dev: Communicate with postgres through the postgres gem 83 | # - postgresql-client-9.4: In case you want to talk directly to postgres 84 | RUN apt-get update && apt-get install -qq -y build-essential nodejs libpq-dev postgresql-client-9.4 --fix-missing --no-install-recommends 85 | 86 | # Set an environment variable to store where the app is installed to inside 87 | # of the Docker image. 88 | ENV INSTALL_PATH /app 89 | RUN mkdir -p $INSTALL_PATH 90 | 91 | # This sets the context of where commands will be ran in and is documented 92 | # on Docker's website extensively. 93 | WORKDIR $INSTALL_PATH 94 | 95 | # (optional/recommended) Environment variables for Dockerized production Rails apps 96 | # ENV RAILS_ENV production 97 | # ENV RAILS_SERVE_STATIC_FILES true 98 | # ENV RAILS_LOG_TO_STDOUT true 99 | 100 | # Ensure gems are cached and only get updated when they change. This will 101 | # drastically increase build times when your gems do not change. 102 | COPY Gemfile Gemfile 103 | COPY Gemfile.lock Gemfile.lock 104 | RUN bundle install --deployment 105 | 106 | # Copy code from working directory outside Docker to working directory inside Docker 107 | COPY . . 108 | #Sometime an extra bundle call is needed to install binaries / native extensions 109 | RUN bundle install --deployment 110 | 111 | # Precompile assets 112 | RUN bundle exec rake DATABASE_URL=postgresql:does_not_exist assets:precompile 113 | 114 | # The default command to start the Unicorn server. 115 | CMD bundle exec puma -p 5000 116 | 117 | Next we'll build the docker image. 118 | 119 | **IMPORTANT** This is the step where you want to make sure you are not consuming conference bandwidth. If you have been developing your app locally and not on the "bridge" box, now is the time to push it up there. Building and pushing docker images consumes significant bandwidth, but if we do it while SSH'd into our "bridge" box we're consuming bandwith on Amazon EC2 instead of locally. 120 | 121 | Connect Docker daemon to docker hub using the `login` command: 122 | 123 | docker login 124 | 125 | Replace `jacobo` in these next few commands with your account name on Docker hub (hub.docker.com), and `myapp` with the name of your rails app. 126 | 127 | Build a docker image and tag it: 128 | 129 | docker build -t jacobo/myapp . 130 | 131 | 132 | Push the tagged image to docker hub: 133 | 134 | docker push jacobo/myapp 135 | 136 | ## 2.5 Test run with docker (optional) 137 | 138 | You should be able to run your app locally inside docker with: 139 | 140 | sudo docker run -d -p 5000:5000 jacobo/myapp 141 | 142 | Needs to be torn-down, for example: 143 | 144 | $ sudo docker ps 145 | CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 146 | 929f6f34b1a1 jacobo/myapp "/bin/sh -c 'bundle e" 2 minutes ago Up 2 minutes 0.0.0.0:5000->5000/tcp romantic_volhard 147 | 148 | $ sudo docker kill 929f6f34b1a1 149 | 150 | ## 3 Deploy on Kubernetes 151 | 152 | Create a deployment (specify your own app name and your own image): 153 | 154 | kubectl run myapp --image=jacobo/myapp --port 5000 155 | 156 | Refer back to [Pods & Services](01-pods-deployments-services.md) and [Secrets & Environment Variables](02-secrets-environment-variables.md) for steps to productionize your app. 157 | -------------------------------------------------------------------------------- /05-blue-green.md: -------------------------------------------------------------------------------- 1 | # The "cool" thing you came for, right? 2 | 3 | https://martinfowler.com/bliki/BlueGreenDeployment.html 4 | 5 | So we know how to edit deployments 6 | 7 | k edit deployments/k8sapp 8 | 9 | We can change the image to deploy different versions 10 | 11 | ... 12 | image: engineyard/k8sapp:v1 13 | ... 14 | 15 | ... 16 | image: engineyard/k8sapp:v2 17 | ... 18 | 19 | And notice it take a little while for the old pods to get rotated and the URL to start returning results from the new version 20 | 21 | k get pods 22 | 23 | NAME READY STATUS RESTARTS AGE 24 | k8sapp-495960030-9jfhw 1/1 Terminating 0 4m 25 | k8sapp-495960030-bf8rj 1/1 Terminating 0 4m 26 | k8sapp-495960030-lnl9t 1/1 Terminating 0 4m 27 | k8sapp-495960030-w9tbl 1/1 Running 0 4m 28 | k8sapp-495960030-zf0mx 1/1 Running 0 4m 29 | k8sapp-576962527-1kqb8 0/1 ContainerCreating 0 0s 30 | k8sapp-576962527-1tmxs 1/1 Running 0 1s 31 | k8sapp-576962527-54pkc 1/1 Running 0 1s 32 | k8sapp-576962527-b389b 0/1 ContainerCreating 0 1s 33 | 34 | curl k8sapp.${ENV_NAME}.my.ey.io 35 | 36 | Let's "fix" that and make deployments instantaneous (or at least feel that way to the user) 37 | 38 | Let's create a blue deployment and a green deployment 39 | 40 | echo "apiVersion: extensions/v1beta1 41 | kind: Deployment 42 | metadata: 43 | name: k8sapp-blue 44 | labels: 45 | app: k8sapp-blue 46 | spec: 47 | strategy: 48 | type: Recreate 49 | template: 50 | metadata: 51 | labels: 52 | app: k8sapp-blue 53 | spec: 54 | containers: 55 | - name: k8sapp-blue 56 | image: engineyard/k8sapp 57 | imagePullPolicy: Always 58 | ports: 59 | - containerPort: 5000 60 | name: k8sapp" | kubectl create -f - 61 | 62 | echo "apiVersion: extensions/v1beta1 63 | kind: Deployment 64 | metadata: 65 | name: k8sapp-green 66 | labels: 67 | app: k8sapp-green 68 | spec: 69 | strategy: 70 | type: Recreate 71 | template: 72 | metadata: 73 | labels: 74 | app: k8sapp-green 75 | spec: 76 | containers: 77 | - name: k8sapp-green 78 | image: engineyard/k8sapp 79 | imagePullPolicy: Always 80 | ports: 81 | - containerPort: 5000 82 | name: k8sapp" | kubectl create -f - 83 | 84 | We can now scale the deployments, change the version of images running in each, and editing the `services/k8sapp` 85 | 86 | Make the `blue` deployment use image `image:engineyard/k8sapp:v1` 87 | 88 | k edit deployments/k8sapp-blue 89 | 90 | change the service to point to `blue` 91 | 92 | k edit services/k8sapp 93 | 94 | ... 95 | selector: 96 | app: k8sapp-blue 97 | 98 | Make the `green` deployment use image `image:engineyard/k8sapp:v2` 99 | 100 | k edit deployments/k8sapp-green 101 | 102 | change the service to point to `green` 103 | 104 | k edit services/k8sapp 105 | 106 | ... 107 | selector: 108 | app: k8sapp-green 109 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Hello! 2 | 3 | Welcome to our Railsconf workshop repository. We'll walkthrough the [Setup](00-setup.md) and 2 exercises together, with you following along on your own kubernetes cluster. ([Pods & Services](01-pods-deployments-services.md) and [Secrets & Environment Variables](02-secrets-environment-variables.md)) Then we'll step back and offer support as you explore on your own. 4 | 5 | You can walkthrough the [Volumes](03-volumes.md) exercise to deploy a containerized database, go straight into [Dockerizing an App](04-dockerize-rails-for-kubernetes.md) (and deploy it on kubernetes), OR investigate other topics (such as the [Topics warranting further investigation](#topics-warranting-further-investigation) at the bottom of this file). If you discover something cool, please share! (in workshop chat, or via spontaneous euphoric vocal exclamation) 6 | 7 | # Prerequisites 8 | 9 | 1. A Working Kubernetes Cluster. (Register for the eventbrite and we'll email you access instruction: http://ey.io/kubey) 10 | 2. A Docker Hub Account. (https://hub.docker.com/) (optional, helps you setup your own apps) 11 | 3. Join the #workshop-chat channel on the Kubernetes slack: http://slack.k8s.io/ (optional, helps you ask questions) 12 | 4. The ability to run SSH and a modern web browser 13 | 14 | Your kubernetes cluster is running on Amazon EC2, backed by Engine Yard. 15 | 16 | Since we are running on conference wifi, and Docker can be bandwidth intensive, we are also giving you access to what we call a "bridge" box. This is a basic EC2 server you can SSH into. It has Ruby and Docker and other basic tools pre-installed. SSH instructions should be available on the Engine Yard dashboard once you get access to one of the accounts we've setup for this workshop. 17 | 18 | Here's some of the pre-installed software on your *bridge* box: 19 | 20 | 1. *ruby* - It's installed with RVM. (You are welcome to install other versions of ruby, see: https://rvm.io/rubies/installing) 21 | 2. *docker* - Will be needed to build and push images to Docker Hub. Kubernetes will then pull these images. 22 | 3. *kubectl* - This is the official kubernetes CLI, it's already setup to talk to your cluster. Here are some commands to try: `kubectl cluster-info` `kubectl get pods --all-namespaces` `kubectl describe service/nginx-ingress -n kube-system` 23 | 4. This repository (already cloned to ~/kubernetes-workshop) 24 | 25 | # Further References 26 | 27 | Feel free to take advantage of the provided kubernetes cluster to explore and run through any random tutorial you find on the internet. Here's a few places you could look: 28 | 29 | * The official Kubernetes git repository examples: https://github.com/kubernetes/kubernetes/tree/master/examples 30 | * An FAQ from somebody doing a lot of Kubernets stuff on AWS: https://github.com/hubt/kubernetes-faq 31 | * A getting started on kubernetes course provided by Google: https://www.udacity.com/course/scalable-microservices-with-kubernetes--ud615 32 | * Some slides from a kubernetes workshop at OSCON: http://Goo.gl/eexNMT 33 | * Helm Charts: https://github.com/kubernetes/helm (TODO there are more URLS here right?) 34 | * https://kubernetes.io/docs/home/ 35 | * 15 kubernetes features in 15 minutes: https://www.youtube.com/watch?v=o85VR90RGNQ 36 | 37 | # Topics warranting further investigation 38 | 39 | (Pull requests welcome) 40 | 41 | * SSL termination 42 | * Asset precompile w/ nginx serving static assets, or CDN (AWS cloudfront) 43 | * Readiness checks vs liveness checks, what happens when a deploy fails, rollback. 44 | * Termination grace period: https://pracucci.com/graceful-shutdown-of-kubernetes-pods.html 45 | * Background tasks (e.g. resque). Use kubernetes job OR just a regular deployment/pods? https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/ 46 | * Taking downtime for migrations. (maintenance page) 47 | * How can we ensure `rake db:migrate` is run exactly once on deploy. (and other deploy hooks) 48 | * Helm (TODO: URL). Package management for kubernetes and templating system for manifest files. 49 | * Using container registries other than docker hub (and private ones with credentials). 50 | * init containers 51 | * multiple pods in a single container (sharing a volume) 52 | * statefulsets 53 | * node-affinity 54 | * daemonsets 55 | * resourcequotas 56 | -------------------------------------------------------------------------------- /code-snippets/Dockerfile: -------------------------------------------------------------------------------- 1 | #The base image, with ruby pre-installed 2 | #see: https://hub.docker.com/_/ruby/ 3 | FROM ruby:2.3 4 | 5 | # Install dependencies: 6 | # - build-essential: To ensure certain gems can be compiled 7 | # - nodejs: Compile assets 8 | # - libpq-dev: Communicate with postgres through the postgres gem 9 | # - postgresql-client-9.4: In case you want to talk directly to postgres 10 | RUN apt-get update && apt-get install -qq -y build-essential nodejs libpq-dev postgresql-client-9.4 --fix-missing --no-install-recommends 11 | 12 | # Set an environment variable to store where the app is installed to inside 13 | # of the Docker image. 14 | ENV INSTALL_PATH /app 15 | RUN mkdir -p $INSTALL_PATH 16 | 17 | # This sets the context of where commands will be ran in and is documented 18 | # on Docker's website extensively. 19 | WORKDIR $INSTALL_PATH 20 | 21 | # (optional/recommended) Environment variables for Dockerized production Rails apps 22 | # ENV RAILS_ENV production 23 | # ENV RAILS_SERVE_STATIC_FILES true 24 | # ENV RAILS_LOG_TO_STDOUT true 25 | 26 | # Ensure gems are cached and only get updated when they change. This will 27 | # drastically increase build times when your gems do not change. 28 | COPY Gemfile Gemfile 29 | COPY Gemfile.lock Gemfile.lock 30 | RUN bundle install --deployment 31 | 32 | # Copy code from working directory outside Docker to working directory inside Docker 33 | COPY . . 34 | #Sometime an extra bundle call is needed to install binaries / native extensions 35 | RUN bundle install --deployment 36 | 37 | # Precompile assets 38 | RUN bundle exec rake DATABASE_URL=postgresql:does_not_exist assets:precompile 39 | 40 | # The default command to start the Unicorn server. 41 | CMD bundle exec puma -p 5000 42 | -------------------------------------------------------------------------------- /code-snippets/database.yml: -------------------------------------------------------------------------------- 1 | # SQLite version 3.x 2 | # gem install sqlite3 3 | # 4 | # Ensure the SQLite 3 gem is defined in your Gemfile 5 | # gem 'sqlite3' 6 | # 7 | default: &default 8 | adapter: postgresql 9 | host: localhost 10 | 11 | development: 12 | <<: *default 13 | database: myapp_dev 14 | 15 | # Warning: The database defined as "test" will be erased and 16 | # re-generated from your development database when you run "rake". 17 | # Do not set this db to the same as development or production. 18 | test: 19 | <<: *default 20 | database: myapp_test 21 | 22 | # RDS DB will provide a DATABASE_URL 23 | <% if ENV['DATABASE_URL'].blank? %> 24 | production: 25 | # DB Service/Deployment provided by k8s will use shared secret (and become admin on the DB) 26 | <<: *default 27 | host: <%= ENV["DB_HOST"] %> 28 | user: postgres 29 | password: <%= ENV["DB_PASSWORD"] %> 30 | database: myapp_prod 31 | <% end %> -------------------------------------------------------------------------------- /code-snippets/hit_counter.rb: -------------------------------------------------------------------------------- 1 | class HitCounter < ApplicationRecord 2 | 3 | #TODO: this is totally NOT the right way to implement a hit counter... 4 | # there are bugs here in race conditions where we could create multiple counters and where we could mis-count hits 5 | 6 | def self.counter 7 | @counter ||= first || create!(hits: 0) 8 | end 9 | 10 | def self.hit! 11 | counter.update(hits: hits + 1) 12 | end 13 | 14 | def self.hits 15 | counter.hits 16 | end 17 | 18 | end 19 | -------------------------------------------------------------------------------- /code-snippets/routes.rb: -------------------------------------------------------------------------------- 1 | Rails.application.routes.draw do 2 | # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html 3 | get "/", :to => "slash#index", :as => :slash 4 | end 5 | -------------------------------------------------------------------------------- /code-snippets/slash_controller.rb: -------------------------------------------------------------------------------- 1 | class SlashController < ApplicationController 2 | 3 | def index 4 | HitCounter.hit! 5 | render json: {"Hit Count" => HitCounter.hits} 6 | end 7 | 8 | end 9 | -------------------------------------------------------------------------------- /graffles/blue-green.graffle: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ActiveLayerIndex 6 | 0 7 | ApplicationVersion 8 | 9 | com.omnigroup.OmniGrafflePro 10 | 139.18.0.187838 11 | 12 | AutoAdjust 13 | 14 | BackgroundGraphic 15 | 16 | Bounds 17 | {{0, 0}, {756, 553}} 18 | Class 19 | SolidGraphic 20 | ID 21 | 2 22 | Style 23 | 24 | shadow 25 | 26 | Draws 27 | NO 28 | 29 | stroke 30 | 31 | Draws 32 | NO 33 | 34 | 35 | 36 | BaseZoom 37 | 0 38 | CanvasOrigin 39 | {0, 0} 40 | ColumnAlign 41 | 1 42 | ColumnSpacing 43 | 36 44 | CreationDate 45 | 2017-04-25 18:48:11 +0000 46 | Creator 47 | Jacob 48 | DisplayScale 49 | 1 0/72 in = 1 0/72 in 50 | GraphDocumentVersion 51 | 8 52 | GraphicsList 53 | 54 | 55 | Class 56 | LineGraphic 57 | Head 58 | 59 | ID 60 | 74 61 | 62 | ID 63 | 91 64 | Points 65 | 66 | {516.69402871355771, 268.60231076075456} 67 | {489.1045278360412, 232.39768635215913} 68 | 69 | Style 70 | 71 | stroke 72 | 73 | HeadArrow 74 | 0 75 | Legacy 76 | 77 | LineType 78 | 1 79 | TailArrow 80 | 0 81 | 82 | 83 | Tail 84 | 85 | ID 86 | 85 87 | 88 | 89 | 90 | Class 91 | LineGraphic 92 | Head 93 | 94 | ID 95 | 74 96 | 97 | ID 98 | 90 99 | Points 100 | 101 | {467.71233964020644, 268.50027419845128} 102 | {468.90512776825017, 232.49972580154875} 103 | 104 | Style 105 | 106 | stroke 107 | 108 | HeadArrow 109 | 0 110 | Legacy 111 | 112 | LineType 113 | 1 114 | TailArrow 115 | 0 116 | 117 | 118 | Tail 119 | 120 | ID 121 | 84 122 | 123 | 124 | 125 | Class 126 | LineGraphic 127 | Head 128 | 129 | ID 130 | 74 131 | 132 | ID 133 | 89 134 | Points 135 | 136 | {418.71352822933648, 268.6149403949953} 137 | {448.72321854456976, 232.38505960500464} 138 | 139 | Style 140 | 141 | stroke 142 | 143 | HeadArrow 144 | 0 145 | Legacy 146 | 147 | LineType 148 | 1 149 | TailArrow 150 | 0 151 | 152 | 153 | Tail 154 | 155 | ID 156 | 83 157 | 158 | 159 | 160 | Class 161 | LineGraphic 162 | Head 163 | 164 | ID 165 | 73 166 | 167 | ID 168 | 88 169 | Points 170 | 171 | {220.65927382114594, 268.53394499362662} 172 | {206.64494309557045, 232.46605500637338} 173 | 174 | Style 175 | 176 | stroke 177 | 178 | HeadArrow 179 | 0 180 | Legacy 181 | 182 | LineType 183 | 1 184 | TailArrow 185 | 0 186 | 187 | 188 | Tail 189 | 190 | ID 191 | 82 192 | 193 | 194 | 195 | Class 196 | LineGraphic 197 | Head 198 | 199 | ID 200 | 73 201 | 202 | ID 203 | 87 204 | Points 205 | 206 | {172.84072481114748, 268.53394499304028} 207 | {186.85505325591038, 232.46605496041227} 208 | 209 | Style 210 | 211 | stroke 212 | 213 | HeadArrow 214 | 0 215 | Legacy 216 | 217 | LineType 218 | 1 219 | TailArrow 220 | 0 221 | 222 | 223 | Tail 224 | 225 | ID 226 | 81 227 | 228 | 229 | 230 | Class 231 | LineGraphic 232 | Head 233 | 234 | ID 235 | 73 236 | 237 | ID 238 | 86 239 | Points 240 | 241 | {117.38895279786342, 271.10673396940831} 242 | {165.41225193343513, 232.31419058038057} 243 | 244 | Style 245 | 246 | stroke 247 | 248 | HeadArrow 249 | 0 250 | Legacy 251 | 252 | LineType 253 | 1 254 | TailArrow 255 | 0 256 | 257 | 258 | Tail 259 | 260 | ID 261 | 80 262 | 263 | 264 | 265 | Bounds 266 | {{510, 269}, {46, 42}} 267 | Class 268 | ShapedGraphic 269 | ID 270 | 85 271 | Shape 272 | Rectangle 273 | Text 274 | 275 | Text 276 | {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf470 277 | \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} 278 | {\colortbl;\red255\green255\blue255;} 279 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc 280 | 281 | \f0\fs24 \cf0 v2\ 282 | Pod} 283 | 284 | 285 | 286 | Bounds 287 | {{444, 269}, {46, 42}} 288 | Class 289 | ShapedGraphic 290 | ID 291 | 84 292 | Shape 293 | Rectangle 294 | Text 295 | 296 | Text 297 | {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf470 298 | \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} 299 | {\colortbl;\red255\green255\blue255;} 300 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc 301 | 302 | \f0\fs24 \cf0 v2\ 303 | Pod} 304 | 305 | 306 | 307 | Bounds 308 | {{378, 269}, {46, 42}} 309 | Class 310 | ShapedGraphic 311 | ID 312 | 83 313 | Shape 314 | Rectangle 315 | Text 316 | 317 | Text 318 | {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf470 319 | \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} 320 | {\colortbl;\red255\green255\blue255;} 321 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc 322 | 323 | \f0\fs24 \cf0 v2\ 324 | Pod} 325 | 326 | 327 | 328 | Bounds 329 | {{206, 269}, {46, 42}} 330 | Class 331 | ShapedGraphic 332 | ID 333 | 82 334 | Shape 335 | Rectangle 336 | Text 337 | 338 | Text 339 | {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf470 340 | \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} 341 | {\colortbl;\red255\green255\blue255;} 342 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc 343 | 344 | \f0\fs24 \cf0 v1\ 345 | Pod} 346 | 347 | 348 | 349 | Bounds 350 | {{141.5, 269}, {46, 42}} 351 | Class 352 | ShapedGraphic 353 | ID 354 | 81 355 | Shape 356 | Rectangle 357 | Text 358 | 359 | Text 360 | {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf470 361 | \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} 362 | {\colortbl;\red255\green255\blue255;} 363 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc 364 | 365 | \f0\fs24 \cf0 v1\ 366 | Pod} 367 | 368 | 369 | 370 | Bounds 371 | {{71, 269}, {46, 42}} 372 | Class 373 | ShapedGraphic 374 | ID 375 | 80 376 | Shape 377 | Rectangle 378 | Text 379 | 380 | Text 381 | {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf470 382 | \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} 383 | {\colortbl;\red255\green255\blue255;} 384 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc 385 | 386 | \f0\fs24 \cf0 v1\ 387 | Pod} 388 | 389 | 390 | 391 | Class 392 | LineGraphic 393 | Head 394 | 395 | ID 396 | 73 397 | 398 | ID 399 | 76 400 | Points 401 | 402 | {301.19801908095184, 114.33183269093131} 403 | {225.30198089718559, 181.66816730906868} 404 | 405 | Style 406 | 407 | stroke 408 | 409 | HeadArrow 410 | FilledArrow 411 | Legacy 412 | 413 | LineType 414 | 1 415 | TailArrow 416 | 0 417 | 418 | 419 | Tail 420 | 421 | ID 422 | 51 423 | 424 | 425 | 426 | Class 427 | LineGraphic 428 | Head 429 | 430 | ID 431 | 74 432 | 433 | ID 434 | 75 435 | Points 436 | 437 | {359.7918490754173, 114.32224539938264} 438 | {439.70124575074504, 181.67779822336118} 439 | 440 | Style 441 | 442 | stroke 443 | 444 | HeadArrow 445 | FilledArrow 446 | Legacy 447 | 448 | LineType 449 | 1 450 | Pattern 451 | 1 452 | TailArrow 453 | 0 454 | 455 | 456 | Tail 457 | 458 | ID 459 | 51 460 | 461 | 462 | 463 | Bounds 464 | {{386, 182}, {167.5, 50}} 465 | Class 466 | ShapedGraphic 467 | ID 468 | 74 469 | Shape 470 | RoundRect 471 | Style 472 | 473 | Text 474 | 475 | Text 476 | {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf470 477 | \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} 478 | {\colortbl;\red255\green255\blue255;} 479 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc 480 | 481 | \f0\fs40 \cf0 Green Deployment} 482 | 483 | 484 | 485 | Bounds 486 | {{113, 182}, {167.5, 50}} 487 | Class 488 | ShapedGraphic 489 | ID 490 | 73 491 | Shape 492 | RoundRect 493 | Style 494 | 495 | Text 496 | 497 | Text 498 | {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf470 499 | \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} 500 | {\colortbl;\red255\green255\blue255;} 501 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc 502 | 503 | \f0\fs40 \cf0 Blue Deployment} 504 | 505 | 506 | 507 | Bounds 508 | {{246, 64}, {167.5, 50}} 509 | Class 510 | ShapedGraphic 511 | ID 512 | 51 513 | Shape 514 | RoundRect 515 | Style 516 | 517 | Text 518 | 519 | Text 520 | {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf470 521 | \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} 522 | {\colortbl;\red255\green255\blue255;} 523 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc 524 | 525 | \f0\fs40 \cf0 Service} 526 | 527 | 528 | 529 | GridInfo 530 | 531 | GuidesLocked 532 | NO 533 | GuidesVisible 534 | YES 535 | HPages 536 | 1 537 | ImageCounter 538 | 1 539 | KeepToScale 540 | 541 | Layers 542 | 543 | 544 | Lock 545 | NO 546 | Name 547 | Layer 1 548 | Print 549 | YES 550 | View 551 | YES 552 | 553 | 554 | LayoutInfo 555 | 556 | Animate 557 | NO 558 | circoMinDist 559 | 18 560 | circoSeparation 561 | 0.0 562 | layoutEngine 563 | dot 564 | neatoSeparation 565 | 0.0 566 | twopiSeparation 567 | 0.0 568 | 569 | LinksVisible 570 | NO 571 | MagnetsVisible 572 | NO 573 | MasterSheets 574 | 575 | ModificationDate 576 | 2017-04-25 18:51:19 +0000 577 | Modifier 578 | Jacob 579 | NotesVisible 580 | NO 581 | Orientation 582 | 2 583 | OriginVisible 584 | NO 585 | PageBreaks 586 | YES 587 | PrintInfo 588 | 589 | NSBottomMargin 590 | 591 | float 592 | 41 593 | 594 | NSHorizonalPagination 595 | 596 | coded 597 | BAtzdHJlYW10eXBlZIHoA4QBQISEhAhOU051bWJlcgCEhAdOU1ZhbHVlAISECE5TT2JqZWN0AIWEASqEhAFxlwCG 598 | 599 | NSLeftMargin 600 | 601 | float 602 | 18 603 | 604 | NSOrientation 605 | 606 | coded 607 | BAtzdHJlYW10eXBlZIHoA4QBQISEhAhOU051bWJlcgCEhAdOU1ZhbHVlAISECE5TT2JqZWN0AIWEASqEhAFxlwGG 608 | 609 | NSPaperSize 610 | 611 | size 612 | {792, 612} 613 | 614 | NSPrintReverseOrientation 615 | 616 | int 617 | 0 618 | 619 | NSRightMargin 620 | 621 | float 622 | 18 623 | 624 | NSTopMargin 625 | 626 | float 627 | 18 628 | 629 | 630 | PrintOnePage 631 | 632 | ReadOnly 633 | NO 634 | RowAlign 635 | 1 636 | RowSpacing 637 | 36 638 | SheetTitle 639 | Canvas 1 640 | SmartAlignmentGuidesActive 641 | YES 642 | SmartDistanceGuidesActive 643 | YES 644 | UniqueID 645 | 1 646 | UseEntirePage 647 | 648 | VPages 649 | 1 650 | WindowInfo 651 | 652 | CurrentSheet 653 | 0 654 | ExpandedCanvases 655 | 656 | 657 | name 658 | Canvas 1 659 | 660 | 661 | Frame 662 | {{231, 54}, {965, 731}} 663 | ListView 664 | 665 | OutlineWidth 666 | 142 667 | RightSidebar 668 | 669 | ShowRuler 670 | 671 | Sidebar 672 | 673 | SidebarWidth 674 | 120 675 | VisibleRegion 676 | {{-37, -18}, {830, 589}} 677 | Zoom 678 | 1 679 | ZoomValues 680 | 681 | 682 | Canvas 1 683 | 1 684 | 1 685 | 686 | 687 | 688 | 689 | 690 | -------------------------------------------------------------------------------- /graffles/kubernetes.graffle: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ActiveLayerIndex 6 | 3 7 | ApplicationVersion 8 | 9 | com.omnigroup.OmniGrafflePro 10 | 139.18.0.187838 11 | 12 | AutoAdjust 13 | 14 | BackgroundGraphic 15 | 16 | Bounds 17 | {{0, 0}, {756, 553}} 18 | Class 19 | SolidGraphic 20 | ID 21 | 2 22 | Style 23 | 24 | shadow 25 | 26 | Draws 27 | NO 28 | 29 | stroke 30 | 31 | Draws 32 | NO 33 | 34 | 35 | 36 | BaseZoom 37 | 0 38 | CanvasOrigin 39 | {0, 0} 40 | ColumnAlign 41 | 1 42 | ColumnSpacing 43 | 36 44 | CreationDate 45 | 2017-04-22 22:15:09 +0000 46 | Creator 47 | Jacob 48 | DisplayScale 49 | 1 0/72 in = 1 0/72 in 50 | GraphDocumentVersion 51 | 8 52 | GraphicsList 53 | 54 | 55 | Class 56 | LineGraphic 57 | ID 58 | 109 59 | Layer 60 | 0 61 | Points 62 | 63 | {426.47876767009149, 53.163705478267161} 64 | {583.51019077031663, 55.617339824883459} 65 | 66 | Style 67 | 68 | stroke 69 | 70 | HeadArrow 71 | FilledArrow 72 | Legacy 73 | 74 | LineType 75 | 1 76 | Pattern 77 | 1 78 | TailArrow 79 | 0 80 | 81 | 82 | 83 | 84 | Bounds 85 | {{589, 14.5}, {53, 14}} 86 | Class 87 | ShapedGraphic 88 | FitText 89 | YES 90 | Flow 91 | Resize 92 | ID 93 | 110 94 | Layer 95 | 0 96 | Shape 97 | Rectangle 98 | Style 99 | 100 | fill 101 | 102 | Draws 103 | NO 104 | 105 | shadow 106 | 107 | Draws 108 | NO 109 | 110 | stroke 111 | 112 | Draws 113 | NO 114 | 115 | 116 | Text 117 | 118 | Pad 119 | 0 120 | Text 121 | {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf470 122 | \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} 123 | {\colortbl;\red255\green255\blue255;} 124 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc 125 | 126 | \f0\fs24 \cf0 Cluster IP} 127 | VerticalPad 128 | 0 129 | 130 | Wrap 131 | NO 132 | 133 | 134 | Class 135 | LineGraphic 136 | Head 137 | 138 | ID 139 | 77 140 | 141 | ID 142 | 108 143 | Layer 144 | 0 145 | Points 146 | 147 | {498.5, 467} 148 | {573.88813781738281, 543} 149 | {742.38812255859375, 473} 150 | {734.5, 162} 151 | {684.72008637699196, 97.894913614235108} 152 | 153 | Style 154 | 155 | stroke 156 | 157 | HeadArrow 158 | FilledArrow 159 | Legacy 160 | 161 | LineType 162 | 1 163 | Pattern 164 | 2 165 | TailArrow 166 | 0 167 | 168 | 169 | 170 | 171 | Bounds 172 | {{616.92425537109375, 83.5}, {32, 14}} 173 | Class 174 | ShapedGraphic 175 | FitText 176 | YES 177 | Flow 178 | Resize 179 | ID 180 | 106 181 | Layer 182 | 0 183 | Shape 184 | Rectangle 185 | Style 186 | 187 | fill 188 | 189 | Draws 190 | NO 191 | 192 | shadow 193 | 194 | Draws 195 | NO 196 | 197 | stroke 198 | 199 | Draws 200 | NO 201 | 202 | 203 | Text 204 | 205 | Pad 206 | 0 207 | Text 208 | {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf470 209 | \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} 210 | {\colortbl;\red255\green255\blue255;} 211 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc 212 | 213 | \f0\fs24 \cf0 labels} 214 | VerticalPad 215 | 0 216 | 217 | Wrap 218 | NO 219 | 220 | 221 | Bounds 222 | {{602.00001925824472, 47.5}, {126, 50}} 223 | Class 224 | ShapedGraphic 225 | ID 226 | 77 227 | Layer 228 | 0 229 | Shape 230 | RoundRect 231 | Style 232 | 233 | Text 234 | 235 | Text 236 | {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf470 237 | \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} 238 | {\colortbl;\red255\green255\blue255;} 239 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc 240 | 241 | \f0\fs40 \cf0 Service(s)} 242 | 243 | 244 | 245 | Bounds 246 | {{593.00001925824472, 38.5}, {121, 50}} 247 | Class 248 | ShapedGraphic 249 | ID 250 | 76 251 | Layer 252 | 0 253 | Shape 254 | RoundRect 255 | Style 256 | 257 | Text 258 | 259 | Text 260 | {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf470 261 | \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} 262 | {\colortbl;\red255\green255\blue255;} 263 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc 264 | 265 | \f0\fs40 \cf0 Service} 266 | 267 | 268 | 269 | Bounds 270 | {{584.00001925824472, 29.5}, {112, 50}} 271 | Class 272 | ShapedGraphic 273 | ID 274 | 75 275 | Layer 276 | 0 277 | Shape 278 | RoundRect 279 | Style 280 | 281 | Text 282 | 283 | Text 284 | {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf470 285 | \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} 286 | {\colortbl;\red255\green255\blue255;} 287 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc 288 | 289 | \f0\fs40 \cf0 Service} 290 | 291 | 292 | 293 | Class 294 | LineGraphic 295 | ID 296 | 80 297 | Layer 298 | 0 299 | Points 300 | 301 | {625.66564986299909, 87.492926103580714} 302 | {615.88815707562753, 145} 303 | {615.88815707562753, 145} 304 | 305 | Style 306 | 307 | stroke 308 | 309 | HeadArrow 310 | 0 311 | Legacy 312 | 313 | TailArrow 314 | 0 315 | 316 | 317 | 318 | 319 | Class 320 | LineGraphic 321 | ID 322 | 79 323 | Layer 324 | 0 325 | Points 326 | 327 | {641.6791189316998, 87.454448006248299} 328 | {669.00001925824472, 147} 329 | {669.00001925824472, 147} 330 | 331 | Style 332 | 333 | stroke 334 | 335 | HeadArrow 336 | 0 337 | Legacy 338 | 339 | TailArrow 340 | 0 341 | 342 | 343 | 344 | 345 | Class 346 | LineGraphic 347 | ID 348 | 78 349 | Layer 350 | 0 351 | Points 352 | 353 | {616.92426260336015, 87.44471565274813} 354 | {593.00001925824472, 134} 355 | 356 | Style 357 | 358 | stroke 359 | 360 | HeadArrow 361 | 0 362 | Legacy 363 | 364 | TailArrow 365 | 0 366 | 367 | 368 | 369 | 370 | Class 371 | LineGraphic 372 | ID 373 | 107 374 | Layer 375 | 1 376 | Points 377 | 378 | {179.2972648968757, 192.48540146500287} 379 | {215.5, 339} 380 | {530.5, 388} 381 | {485.88813781738281, 435} 382 | 383 | Style 384 | 385 | stroke 386 | 387 | HeadArrow 388 | 0 389 | Legacy 390 | 391 | TailArrow 392 | 0 393 | 394 | 395 | 396 | 397 | Bounds 398 | {{497, 435}, {72, 28}} 399 | Class 400 | ShapedGraphic 401 | FitText 402 | YES 403 | Flow 404 | Resize 405 | ID 406 | 64 407 | Layer 408 | 1 409 | Shape 410 | Rectangle 411 | Style 412 | 413 | fill 414 | 415 | Draws 416 | NO 417 | 418 | shadow 419 | 420 | Draws 421 | NO 422 | 423 | stroke 424 | 425 | Draws 426 | NO 427 | 428 | 429 | Text 430 | 431 | Pad 432 | 0 433 | Text 434 | {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf470 435 | \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} 436 | {\colortbl;\red255\green255\blue255;} 437 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc 438 | 439 | \f0\fs24 \cf0 kube-system \ 440 | nginx-ingress} 441 | VerticalPad 442 | 0 443 | 444 | Wrap 445 | NO 446 | 447 | 448 | Class 449 | LineGraphic 450 | Head 451 | 452 | ID 453 | 51 454 | 455 | ID 456 | 67 457 | Layer 458 | 1 459 | Points 460 | 461 | {313.1773042777512, 75.272771868131414} 462 | {211.08851634441643, 141.72673916044707} 463 | 464 | Style 465 | 466 | stroke 467 | 468 | HeadArrow 469 | FilledArrow 470 | Legacy 471 | 472 | LineType 473 | 1 474 | Pattern 475 | 1 476 | TailArrow 477 | 0 478 | 479 | 480 | Tail 481 | 482 | ID 483 | 54 484 | 485 | 486 | 487 | Bounds 488 | {{104, 143}, {143, 14}} 489 | Class 490 | ShapedGraphic 491 | FitText 492 | YES 493 | Flow 494 | Resize 495 | ID 496 | 65 497 | Layer 498 | 1 499 | Shape 500 | Rectangle 501 | Style 502 | 503 | fill 504 | 505 | Draws 506 | NO 507 | 508 | shadow 509 | 510 | Draws 511 | NO 512 | 513 | stroke 514 | 515 | Draws 516 | NO 517 | 518 | 519 | Text 520 | 521 | Pad 522 | 0 523 | Text 524 | {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf470 525 | \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} 526 | {\colortbl;\red255\green255\blue255;} 527 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc 528 | 529 | \f0\fs24 \cf0 kube-system nginx-ingress} 530 | VerticalPad 531 | 0 532 | 533 | Wrap 534 | NO 535 | 536 | 537 | Bounds 538 | {{514, 260.5}, {143, 14}} 539 | Class 540 | ShapedGraphic 541 | FitText 542 | YES 543 | Flow 544 | Resize 545 | ID 546 | 62 547 | Layer 548 | 1 549 | Shape 550 | Rectangle 551 | Style 552 | 553 | fill 554 | 555 | Draws 556 | NO 557 | 558 | shadow 559 | 560 | Draws 561 | NO 562 | 563 | stroke 564 | 565 | Draws 566 | NO 567 | 568 | 569 | Text 570 | 571 | Pad 572 | 0 573 | Text 574 | {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf470 575 | \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} 576 | {\colortbl;\red255\green255\blue255;} 577 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc 578 | 579 | \f0\fs24 \cf0 kube-system nginx-ingress} 580 | VerticalPad 581 | 0 582 | 583 | Wrap 584 | NO 585 | 586 | 587 | Bounds 588 | {{300, 260.5}, {143, 14}} 589 | Class 590 | ShapedGraphic 591 | FitText 592 | YES 593 | Flow 594 | Resize 595 | ID 596 | 61 597 | Layer 598 | 1 599 | Shape 600 | Rectangle 601 | Style 602 | 603 | fill 604 | 605 | Draws 606 | NO 607 | 608 | shadow 609 | 610 | Draws 611 | NO 612 | 613 | stroke 614 | 615 | Draws 616 | NO 617 | 618 | 619 | Text 620 | 621 | Pad 622 | 0 623 | Text 624 | {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf470 625 | \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} 626 | {\colortbl;\red255\green255\blue255;} 627 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc 628 | 629 | \f0\fs24 \cf0 kube-system nginx-ingress} 630 | VerticalPad 631 | 0 632 | 633 | Wrap 634 | NO 635 | 636 | 637 | Bounds 638 | {{410.5, 119}, {143, 14}} 639 | Class 640 | ShapedGraphic 641 | FitText 642 | YES 643 | Flow 644 | Resize 645 | ID 646 | 60 647 | Layer 648 | 1 649 | Shape 650 | Rectangle 651 | Style 652 | 653 | fill 654 | 655 | Draws 656 | NO 657 | 658 | shadow 659 | 660 | Draws 661 | NO 662 | 663 | stroke 664 | 665 | Draws 666 | NO 667 | 668 | 669 | Text 670 | 671 | Pad 672 | 0 673 | Text 674 | {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf470 675 | \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} 676 | {\colortbl;\red255\green255\blue255;} 677 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc 678 | 679 | \f0\fs24 \cf0 kube-system nginx-ingress} 680 | VerticalPad 681 | 0 682 | 683 | Wrap 684 | NO 685 | 686 | 687 | Bounds 688 | {{278.00217437744141, 25}, {148, 50}} 689 | Class 690 | ShapedGraphic 691 | ID 692 | 54 693 | Layer 694 | 1 695 | Shape 696 | RoundRect 697 | Style 698 | 699 | Text 700 | 701 | Text 702 | {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf470 703 | \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} 704 | {\colortbl;\red255\green255\blue255;} 705 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc 706 | 707 | \f0\fs40 \cf0 Ingress} 708 | 709 | 710 | 711 | Bounds 712 | {{136.38815307617188, 198}, {43, 14}} 713 | Class 714 | ShapedGraphic 715 | FitText 716 | YES 717 | Flow 718 | Resize 719 | ID 720 | 104 721 | Layer 722 | 2 723 | Shape 724 | Rectangle 725 | Style 726 | 727 | fill 728 | 729 | Draws 730 | NO 731 | 732 | shadow 733 | 734 | Draws 735 | NO 736 | 737 | stroke 738 | 739 | Draws 740 | NO 741 | 742 | 743 | Text 744 | 745 | Pad 746 | 0 747 | Text 748 | {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf470 749 | \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} 750 | {\colortbl;\red255\green255\blue255;} 751 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc 752 | 753 | \f0\fs24 \cf0 selector} 754 | VerticalPad 755 | 0 756 | 757 | Wrap 758 | NO 759 | 760 | 761 | Class 762 | LineGraphic 763 | ID 764 | 57 765 | Layer 766 | 2 767 | Points 768 | 769 | {190.54431696711842, 192.44135214093865} 770 | {251, 306} 771 | {703, 394} 772 | 773 | Style 774 | 775 | stroke 776 | 777 | HeadArrow 778 | 0 779 | Legacy 780 | 781 | TailArrow 782 | 0 783 | 784 | 785 | 786 | 787 | Class 788 | LineGraphic 789 | ID 790 | 56 791 | Layer 792 | 2 793 | Points 794 | 795 | {185.08222925239244, 192.47659220862835} 796 | {223, 312} 797 | {529, 405} 798 | {495, 435} 799 | 800 | Style 801 | 802 | stroke 803 | 804 | HeadArrow 805 | 0 806 | Legacy 807 | 808 | TailArrow 809 | 0 810 | 811 | 812 | 813 | 814 | Class 815 | LineGraphic 816 | ID 817 | 55 818 | Layer 819 | 2 820 | Points 821 | 822 | {181.30625265226607, 192.49301570141512} 823 | {202, 315} 824 | {401, 405} 825 | {343, 446} 826 | 827 | Style 828 | 829 | stroke 830 | 831 | HeadArrow 832 | 0 833 | Legacy 834 | 835 | TailArrow 836 | 0 837 | 838 | 839 | 840 | 841 | Class 842 | LineGraphic 843 | Head 844 | 845 | ID 846 | 51 847 | 848 | ID 849 | 72 850 | Layer 851 | 3 852 | Points 853 | 854 | {91.381473767520944, 95.78287833442451} 855 | {143.43476735728299, 141.67061372832322} 856 | 857 | Style 858 | 859 | stroke 860 | 861 | HeadArrow 862 | FilledArrow 863 | Legacy 864 | 865 | LineType 866 | 1 867 | Pattern 868 | 1 869 | TailArrow 870 | 0 871 | 872 | 873 | Tail 874 | 875 | ID 876 | 69 877 | 878 | 879 | 880 | Bounds 881 | {{21, 29}, {80, 80}} 882 | Class 883 | ShapedGraphic 884 | FontInfo 885 | 886 | Font 887 | Helvetica 888 | Size 889 | 12 890 | 891 | ID 892 | 69 893 | Layer 894 | 3 895 | Shape 896 | Circle 897 | Style 898 | 899 | Text 900 | 901 | Text 902 | {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf470 903 | \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} 904 | {\colortbl;\red255\green255\blue255;} 905 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc 906 | 907 | \f0\fs26 \cf0 Load\ 908 | Balancer} 909 | 910 | 911 | 912 | Bounds 913 | {{88.611846923828125, 142}, {167.5, 50}} 914 | Class 915 | ShapedGraphic 916 | ID 917 | 51 918 | Layer 919 | 3 920 | Shape 921 | RoundRect 922 | Style 923 | 924 | Text 925 | 926 | Text 927 | {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf470 928 | \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} 929 | {\colortbl;\red255\green255\blue255;} 930 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc 931 | 932 | \f0\fs40 \cf0 Service} 933 | 934 | 935 | 936 | Bounds 937 | {{431, 460}, {32, 14}} 938 | Class 939 | ShapedGraphic 940 | FitText 941 | YES 942 | Flow 943 | Resize 944 | ID 945 | 96 946 | Layer 947 | 4 948 | Shape 949 | Rectangle 950 | Style 951 | 952 | fill 953 | 954 | Draws 955 | NO 956 | 957 | shadow 958 | 959 | Draws 960 | NO 961 | 962 | stroke 963 | 964 | Draws 965 | NO 966 | 967 | 968 | Text 969 | 970 | Pad 971 | 0 972 | Text 973 | {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf470 974 | \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} 975 | {\colortbl;\red255\green255\blue255;} 976 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc 977 | 978 | \f0\fs24 \cf0 labels} 979 | VerticalPad 980 | 0 981 | 982 | Wrap 983 | NO 984 | 985 | 986 | Bounds 987 | {{269, 464}, {32, 14}} 988 | Class 989 | ShapedGraphic 990 | FitText 991 | YES 992 | Flow 993 | Resize 994 | ID 995 | 95 996 | Layer 997 | 4 998 | Shape 999 | Rectangle 1000 | Style 1001 | 1002 | fill 1003 | 1004 | Draws 1005 | NO 1006 | 1007 | shadow 1008 | 1009 | Draws 1010 | NO 1011 | 1012 | stroke 1013 | 1014 | Draws 1015 | NO 1016 | 1017 | 1018 | Text 1019 | 1020 | Pad 1021 | 0 1022 | Text 1023 | {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf470 1024 | \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} 1025 | {\colortbl;\red255\green255\blue255;} 1026 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc 1027 | 1028 | \f0\fs24 \cf0 labels} 1029 | VerticalPad 1030 | 0 1031 | 1032 | Wrap 1033 | NO 1034 | 1035 | 1036 | Bounds 1037 | {{617, 467.5}, {32, 14}} 1038 | Class 1039 | ShapedGraphic 1040 | FitText 1041 | YES 1042 | Flow 1043 | Resize 1044 | ID 1045 | 94 1046 | Layer 1047 | 4 1048 | Shape 1049 | Rectangle 1050 | Style 1051 | 1052 | fill 1053 | 1054 | Draws 1055 | NO 1056 | 1057 | shadow 1058 | 1059 | Draws 1060 | NO 1061 | 1062 | stroke 1063 | 1064 | Draws 1065 | NO 1066 | 1067 | 1068 | Text 1069 | 1070 | Pad 1071 | 0 1072 | Text 1073 | {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf470 1074 | \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} 1075 | {\colortbl;\red255\green255\blue255;} 1076 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc 1077 | 1078 | \f0\fs24 \cf0 labels} 1079 | VerticalPad 1080 | 0 1081 | 1082 | Wrap 1083 | NO 1084 | 1085 | 1086 | Bounds 1087 | {{453, 471.5}, {32, 14}} 1088 | Class 1089 | ShapedGraphic 1090 | FitText 1091 | YES 1092 | Flow 1093 | Resize 1094 | ID 1095 | 93 1096 | Layer 1097 | 4 1098 | Shape 1099 | Rectangle 1100 | Style 1101 | 1102 | fill 1103 | 1104 | Draws 1105 | NO 1106 | 1107 | shadow 1108 | 1109 | Draws 1110 | NO 1111 | 1112 | stroke 1113 | 1114 | Draws 1115 | NO 1116 | 1117 | 1118 | Text 1119 | 1120 | Pad 1121 | 0 1122 | Text 1123 | {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf470 1124 | \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} 1125 | {\colortbl;\red255\green255\blue255;} 1126 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc 1127 | 1128 | \f0\fs24 \cf0 labels} 1129 | VerticalPad 1130 | 0 1131 | 1132 | Wrap 1133 | NO 1134 | 1135 | 1136 | Bounds 1137 | {{289, 475}, {32, 14}} 1138 | Class 1139 | ShapedGraphic 1140 | FitText 1141 | YES 1142 | Flow 1143 | Resize 1144 | ID 1145 | 92 1146 | Layer 1147 | 4 1148 | Shape 1149 | Rectangle 1150 | Style 1151 | 1152 | fill 1153 | 1154 | Draws 1155 | NO 1156 | 1157 | shadow 1158 | 1159 | Draws 1160 | NO 1161 | 1162 | stroke 1163 | 1164 | Draws 1165 | NO 1166 | 1167 | 1168 | Text 1169 | 1170 | Pad 1171 | 0 1172 | Text 1173 | {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf470 1174 | \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} 1175 | {\colortbl;\red255\green255\blue255;} 1176 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc 1177 | 1178 | \f0\fs24 \cf0 labels} 1179 | VerticalPad 1180 | 0 1181 | 1182 | Wrap 1183 | NO 1184 | 1185 | 1186 | Bounds 1187 | {{328, 481}, {32, 14}} 1188 | Class 1189 | ShapedGraphic 1190 | FitText 1191 | YES 1192 | Flow 1193 | Resize 1194 | ID 1195 | 91 1196 | Layer 1197 | 4 1198 | Shape 1199 | Rectangle 1200 | Style 1201 | 1202 | fill 1203 | 1204 | Draws 1205 | NO 1206 | 1207 | shadow 1208 | 1209 | Draws 1210 | NO 1211 | 1212 | stroke 1213 | 1214 | Draws 1215 | NO 1216 | 1217 | 1218 | Text 1219 | 1220 | Pad 1221 | 0 1222 | Text 1223 | {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf470 1224 | \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} 1225 | {\colortbl;\red255\green255\blue255;} 1226 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc 1227 | 1228 | \f0\fs24 \cf0 labels} 1229 | VerticalPad 1230 | 0 1231 | 1232 | Wrap 1233 | NO 1234 | 1235 | 1236 | Bounds 1237 | {{606.5, 307}, {43, 14}} 1238 | Class 1239 | ShapedGraphic 1240 | FitText 1241 | YES 1242 | Flow 1243 | Resize 1244 | ID 1245 | 90 1246 | Layer 1247 | 4 1248 | Shape 1249 | Rectangle 1250 | Style 1251 | 1252 | fill 1253 | 1254 | Draws 1255 | NO 1256 | 1257 | shadow 1258 | 1259 | Draws 1260 | NO 1261 | 1262 | stroke 1263 | 1264 | Draws 1265 | NO 1266 | 1267 | 1268 | Text 1269 | 1270 | Pad 1271 | 0 1272 | Text 1273 | {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf470 1274 | \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} 1275 | {\colortbl;\red255\green255\blue255;} 1276 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc 1277 | 1278 | \f0\fs24 \cf0 selector} 1279 | VerticalPad 1280 | 0 1281 | 1282 | Wrap 1283 | NO 1284 | 1285 | 1286 | Bounds 1287 | {{392, 307}, {43, 14}} 1288 | Class 1289 | ShapedGraphic 1290 | FitText 1291 | YES 1292 | Flow 1293 | Resize 1294 | ID 1295 | 89 1296 | Layer 1297 | 4 1298 | Shape 1299 | Rectangle 1300 | Style 1301 | 1302 | fill 1303 | 1304 | Draws 1305 | NO 1306 | 1307 | shadow 1308 | 1309 | Draws 1310 | NO 1311 | 1312 | stroke 1313 | 1314 | Draws 1315 | NO 1316 | 1317 | 1318 | Text 1319 | 1320 | Pad 1321 | 0 1322 | Text 1323 | {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf470 1324 | \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} 1325 | {\colortbl;\red255\green255\blue255;} 1326 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc 1327 | 1328 | \f0\fs24 \cf0 selector} 1329 | VerticalPad 1330 | 0 1331 | 1332 | Wrap 1333 | NO 1334 | 1335 | 1336 | Bounds 1337 | {{465, 104}, {32, 14}} 1338 | Class 1339 | ShapedGraphic 1340 | FitText 1341 | YES 1342 | Flow 1343 | Resize 1344 | ID 1345 | 88 1346 | Layer 1347 | 4 1348 | Shape 1349 | Rectangle 1350 | Style 1351 | 1352 | fill 1353 | 1354 | Draws 1355 | NO 1356 | 1357 | shadow 1358 | 1359 | Draws 1360 | NO 1361 | 1362 | stroke 1363 | 1364 | Draws 1365 | NO 1366 | 1367 | 1368 | Text 1369 | 1370 | Pad 1371 | 0 1372 | Text 1373 | {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf470 1374 | \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} 1375 | {\colortbl;\red255\green255\blue255;} 1376 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc 1377 | 1378 | \f0\fs24 \cf0 labels} 1379 | VerticalPad 1380 | 0 1381 | 1382 | Wrap 1383 | NO 1384 | 1385 | 1386 | Bounds 1387 | {{569, 244}, {32, 14}} 1388 | Class 1389 | ShapedGraphic 1390 | FitText 1391 | YES 1392 | Flow 1393 | Resize 1394 | ID 1395 | 86 1396 | Layer 1397 | 4 1398 | Shape 1399 | Rectangle 1400 | Style 1401 | 1402 | fill 1403 | 1404 | Draws 1405 | NO 1406 | 1407 | shadow 1408 | 1409 | Draws 1410 | NO 1411 | 1412 | stroke 1413 | 1414 | Draws 1415 | NO 1416 | 1417 | 1418 | Text 1419 | 1420 | Pad 1421 | 0 1422 | Text 1423 | {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf470 1424 | \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} 1425 | {\colortbl;\red255\green255\blue255;} 1426 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc 1427 | 1428 | \f0\fs24 \cf0 labels} 1429 | VerticalPad 1430 | 0 1431 | 1432 | Wrap 1433 | NO 1434 | 1435 | 1436 | Bounds 1437 | {{367, 244}, {32, 14}} 1438 | Class 1439 | ShapedGraphic 1440 | FitText 1441 | YES 1442 | Flow 1443 | Resize 1444 | ID 1445 | 85 1446 | Layer 1447 | 4 1448 | Shape 1449 | Rectangle 1450 | Style 1451 | 1452 | fill 1453 | 1454 | Draws 1455 | NO 1456 | 1457 | shadow 1458 | 1459 | Draws 1460 | NO 1461 | 1462 | stroke 1463 | 1464 | Draws 1465 | NO 1466 | 1467 | 1468 | Text 1469 | 1470 | Pad 1471 | 0 1472 | Text 1473 | {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf470 1474 | \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} 1475 | {\colortbl;\red255\green255\blue255;} 1476 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc 1477 | 1478 | \f0\fs24 \cf0 labels} 1479 | VerticalPad 1480 | 0 1481 | 1482 | Wrap 1483 | NO 1484 | 1485 | 1486 | Bounds 1487 | {{463.5, 173}, {43, 14}} 1488 | Class 1489 | ShapedGraphic 1490 | FitText 1491 | YES 1492 | Flow 1493 | Resize 1494 | ID 1495 | 83 1496 | Layer 1497 | 4 1498 | Shape 1499 | Rectangle 1500 | Style 1501 | 1502 | fill 1503 | 1504 | Draws 1505 | NO 1506 | 1507 | shadow 1508 | 1509 | Draws 1510 | NO 1511 | 1512 | stroke 1513 | 1514 | Draws 1515 | NO 1516 | 1517 | 1518 | Text 1519 | 1520 | Pad 1521 | 0 1522 | Text 1523 | {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf470 1524 | \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} 1525 | {\colortbl;\red255\green255\blue255;} 1526 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc 1527 | 1528 | \f0\fs24 \cf0 selector} 1529 | VerticalPad 1530 | 0 1531 | 1532 | Wrap 1533 | NO 1534 | 1535 | 1536 | Class 1537 | LineGraphic 1538 | ID 1539 | 50 1540 | Layer 1541 | 5 1542 | Points 1543 | 1544 | {582.49165073327197, 307.4944963029094} 1545 | {573.88813781738281, 365} 1546 | {573.88813781738281, 365} 1547 | 1548 | Style 1549 | 1550 | stroke 1551 | 1552 | HeadArrow 1553 | 0 1554 | Legacy 1555 | 1556 | TailArrow 1557 | 0 1558 | 1559 | 1560 | Tail 1561 | 1562 | ID 1563 | 46 1564 | 1565 | 1566 | 1567 | Class 1568 | LineGraphic 1569 | ID 1570 | 49 1571 | Layer 1572 | 5 1573 | Points 1574 | 1575 | {598.4906849276864, 307.45098056756552} 1576 | {627, 367} 1577 | {627, 367} 1578 | 1579 | Style 1580 | 1581 | stroke 1582 | 1583 | HeadArrow 1584 | 0 1585 | Legacy 1586 | 1587 | TailArrow 1588 | 0 1589 | 1590 | 1591 | Tail 1592 | 1593 | ID 1594 | 46 1595 | 1596 | 1597 | 1598 | Class 1599 | LineGraphic 1600 | ID 1601 | 48 1602 | Layer 1603 | 5 1604 | Points 1605 | 1606 | {573.82679053997254, 307.4489312422312} 1607 | {551, 354} 1608 | 1609 | Style 1610 | 1611 | stroke 1612 | 1613 | HeadArrow 1614 | 0 1615 | Legacy 1616 | 1617 | TailArrow 1618 | 0 1619 | 1620 | 1621 | Tail 1622 | 1623 | ID 1624 | 46 1625 | 1626 | 1627 | 1628 | Class 1629 | LineGraphic 1630 | Head 1631 | 1632 | ID 1633 | 46 1634 | 1635 | ID 1636 | 47 1637 | Layer 1638 | 5 1639 | Points 1640 | 1641 | {500.21118338366563, 168.39877503523095} 1642 | {566.9269176903332, 256.60249955987638} 1643 | 1644 | Style 1645 | 1646 | stroke 1647 | 1648 | HeadArrow 1649 | 0 1650 | Legacy 1651 | 1652 | TailArrow 1653 | 0 1654 | 1655 | 1656 | Tail 1657 | 1658 | ID 1659 | 44 1660 | 1661 | 1662 | 1663 | Bounds 1664 | {{503.61184692382812, 257}, {165.38817233441659, 50}} 1665 | Class 1666 | ShapedGraphic 1667 | ID 1668 | 46 1669 | Layer 1670 | 5 1671 | Shape 1672 | RoundRect 1673 | Style 1674 | 1675 | Text 1676 | 1677 | Text 1678 | {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf470 1679 | \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} 1680 | {\colortbl;\red255\green255\blue255;} 1681 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc 1682 | 1683 | \f0\fs40 \cf0 Replica Set} 1684 | 1685 | 1686 | 1687 | Class 1688 | LineGraphic 1689 | Head 1690 | 1691 | ID 1692 | 39 1693 | 1694 | ID 1695 | 45 1696 | Layer 1697 | 5 1698 | Points 1699 | 1700 | {460.4922436329183, 168.38896094651477} 1701 | {389.23163350628931, 256.6108422262202} 1702 | 1703 | Style 1704 | 1705 | stroke 1706 | 1707 | HeadArrow 1708 | 0 1709 | Legacy 1710 | 1711 | TailArrow 1712 | 0 1713 | 1714 | 1715 | Tail 1716 | 1717 | ID 1718 | 44 1719 | 1720 | 1721 | 1722 | Bounds 1723 | {{407, 118}, {148, 50}} 1724 | Class 1725 | ShapedGraphic 1726 | ID 1727 | 44 1728 | Layer 1729 | 5 1730 | Shape 1731 | RoundRect 1732 | Style 1733 | 1734 | Text 1735 | 1736 | Text 1737 | {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf470 1738 | \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} 1739 | {\colortbl;\red255\green255\blue255;} 1740 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc 1741 | 1742 | \f0\fs40 \cf0 Deployment} 1743 | 1744 | 1745 | 1746 | Class 1747 | LineGraphic 1748 | ID 1749 | 43 1750 | Layer 1751 | 6 1752 | Points 1753 | 1754 | {360.41589208410232, 307.47521640517573} 1755 | {317.38812255859375, 439} 1756 | {317.38812255859375, 439} 1757 | 1758 | Style 1759 | 1760 | stroke 1761 | 1762 | HeadArrow 1763 | 0 1764 | Legacy 1765 | 1766 | TailArrow 1767 | 0 1768 | 1769 | 1770 | Tail 1771 | 1772 | ID 1773 | 39 1774 | 1775 | 1776 | 1777 | Class 1778 | LineGraphic 1779 | ID 1780 | 42 1781 | Layer 1782 | 6 1783 | Points 1784 | 1785 | {382.86673746534814, 307.43718827621836} 1786 | {447, 423} 1787 | {447, 423} 1788 | 1789 | Style 1790 | 1791 | stroke 1792 | 1793 | HeadArrow 1794 | 0 1795 | Legacy 1796 | 1797 | TailArrow 1798 | 0 1799 | 1800 | 1801 | Tail 1802 | 1803 | ID 1804 | 39 1805 | 1806 | 1807 | 1808 | Class 1809 | LineGraphic 1810 | ID 1811 | 41 1812 | Layer 1813 | 6 1814 | Points 1815 | 1816 | {354.45299484677219, 307.4358658845486} 1817 | {285, 431} 1818 | {285, 431} 1819 | 1820 | Style 1821 | 1822 | stroke 1823 | 1824 | HeadArrow 1825 | 0 1826 | Legacy 1827 | 1828 | TailArrow 1829 | 0 1830 | 1831 | 1832 | Tail 1833 | 1834 | ID 1835 | 39 1836 | 1837 | 1838 | 1839 | Bounds 1840 | {{285, 257}, {167.5, 50}} 1841 | Class 1842 | ShapedGraphic 1843 | ID 1844 | 39 1845 | Layer 1846 | 6 1847 | Shape 1848 | RoundRect 1849 | Style 1850 | 1851 | Text 1852 | 1853 | Text 1854 | {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf470 1855 | \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} 1856 | {\colortbl;\red255\green255\blue255;} 1857 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc 1858 | 1859 | \f0\fs40 \cf0 Replica Set} 1860 | 1861 | 1862 | 1863 | Bounds 1864 | {{603, 431}, {50, 50}} 1865 | Class 1866 | ShapedGraphic 1867 | FontInfo 1868 | 1869 | Font 1870 | Helvetica 1871 | Size 1872 | 20 1873 | 1874 | ID 1875 | 38 1876 | Layer 1877 | 7 1878 | Shape 1879 | Rectangle 1880 | Text 1881 | 1882 | Text 1883 | {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf470 1884 | \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} 1885 | {\colortbl;\red255\green255\blue255;} 1886 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc 1887 | 1888 | \f0\fs42 \cf0 Pod} 1889 | 1890 | 1891 | 1892 | Bounds 1893 | {{447, 435}, {50, 50}} 1894 | Class 1895 | ShapedGraphic 1896 | FontInfo 1897 | 1898 | Font 1899 | Helvetica 1900 | Size 1901 | 20 1902 | 1903 | ID 1904 | 37 1905 | Layer 1906 | 7 1907 | Shape 1908 | Rectangle 1909 | Text 1910 | 1911 | Text 1912 | {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf470 1913 | \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} 1914 | {\colortbl;\red255\green255\blue255;} 1915 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc 1916 | 1917 | \f0\fs42 \cf0 Pod} 1918 | 1919 | 1920 | 1921 | Bounds 1922 | {{422, 424}, {50, 50}} 1923 | Class 1924 | ShapedGraphic 1925 | FontInfo 1926 | 1927 | Font 1928 | Helvetica 1929 | Size 1930 | 20 1931 | 1932 | ID 1933 | 36 1934 | Layer 1935 | 7 1936 | Shape 1937 | Rectangle 1938 | Text 1939 | 1940 | Text 1941 | {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf470 1942 | \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} 1943 | {\colortbl;\red255\green255\blue255;} 1944 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc 1945 | 1946 | \f0\fs42 \cf0 Pod} 1947 | 1948 | 1949 | 1950 | Bounds 1951 | {{310, 446}, {50, 50}} 1952 | Class 1953 | ShapedGraphic 1954 | FontInfo 1955 | 1956 | Font 1957 | Helvetica 1958 | Size 1959 | 20 1960 | 1961 | ID 1962 | 35 1963 | Layer 1964 | 7 1965 | Shape 1966 | Rectangle 1967 | Text 1968 | 1969 | Text 1970 | {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf470 1971 | \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} 1972 | {\colortbl;\red255\green255\blue255;} 1973 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc 1974 | 1975 | \f0\fs42 \cf0 Pod} 1976 | 1977 | 1978 | 1979 | Bounds 1980 | {{285, 439}, {50, 50}} 1981 | Class 1982 | ShapedGraphic 1983 | FontInfo 1984 | 1985 | Font 1986 | Helvetica 1987 | Size 1988 | 20 1989 | 1990 | ID 1991 | 34 1992 | Layer 1993 | 7 1994 | Shape 1995 | Rectangle 1996 | Text 1997 | 1998 | Text 1999 | {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf470 2000 | \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} 2001 | {\colortbl;\red255\green255\blue255;} 2002 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc 2003 | 2004 | \f0\fs42 \cf0 Pod} 2005 | 2006 | 2007 | 2008 | Bounds 2009 | {{260, 431}, {50, 50}} 2010 | Class 2011 | ShapedGraphic 2012 | FontInfo 2013 | 2014 | Font 2015 | Helvetica 2016 | Size 2017 | 20 2018 | 2019 | ID 2020 | 32 2021 | Layer 2022 | 7 2023 | Shape 2024 | Rectangle 2025 | Text 2026 | 2027 | Text 2028 | {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf470 2029 | \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} 2030 | {\colortbl;\red255\green255\blue255;} 2031 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc 2032 | 2033 | \f0\fs42 \cf0 Pod} 2034 | 2035 | 2036 | 2037 | Class 2038 | LineGraphic 2039 | Head 2040 | 2041 | ID 2042 | 17 2043 | 2044 | ID 2045 | 31 2046 | Layer 2047 | 8 2048 | Points 2049 | 2050 | {77.491550435788724, 339.50002118058899} 2051 | {77.475410830322303, 424.50000072337554} 2052 | 2053 | Style 2054 | 2055 | stroke 2056 | 2057 | HeadArrow 2058 | FilledArrow 2059 | Legacy 2060 | 2061 | LineType 2062 | 1 2063 | Pattern 2064 | 1 2065 | TailArrow 2066 | 0 2067 | 2068 | 2069 | Tail 2070 | 2071 | ID 2072 | 30 2073 | 2074 | 2075 | 2076 | Bounds 2077 | {{33.5, 251}, {88, 88}} 2078 | Class 2079 | ShapedGraphic 2080 | ID 2081 | 30 2082 | Layer 2083 | 8 2084 | Shape 2085 | Circle 2086 | Style 2087 | 2088 | Text 2089 | 2090 | Text 2091 | {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf470 2092 | \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} 2093 | {\colortbl;\red255\green255\blue255;} 2094 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc 2095 | 2096 | \f0\fs38 \cf0 kubectl} 2097 | 2098 | 2099 | 2100 | Bounds 2101 | {{584, 388}, {63, 28}} 2102 | Class 2103 | ShapedGraphic 2104 | ID 2105 | 26 2106 | Layer 2107 | 8 2108 | Shape 2109 | RoundRect 2110 | Style 2111 | 2112 | Text 2113 | 2114 | Align 2115 | 0 2116 | Text 2117 | {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf470 2118 | \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} 2119 | {\colortbl;\red255\green255\blue255;} 2120 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural 2121 | 2122 | \f0\fs24 \cf0 kubelet} 2123 | 2124 | 2125 | 2126 | Bounds 2127 | {{654.38812255859375, 388}, {88, 28}} 2128 | Class 2129 | ShapedGraphic 2130 | ID 2131 | 25 2132 | Layer 2133 | 8 2134 | Shape 2135 | RoundRect 2136 | Style 2137 | 2138 | Text 2139 | 2140 | Align 2141 | 0 2142 | Text 2143 | {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf470 2144 | \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} 2145 | {\colortbl;\red255\green255\blue255;} 2146 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural 2147 | 2148 | \f0\fs24 \cf0 kube-proxy} 2149 | 2150 | 2151 | 2152 | Bounds 2153 | {{415.50001525878906, 388}, {63, 28}} 2154 | Class 2155 | ShapedGraphic 2156 | ID 2157 | 24 2158 | Layer 2159 | 8 2160 | Shape 2161 | RoundRect 2162 | Style 2163 | 2164 | Text 2165 | 2166 | Align 2167 | 0 2168 | Text 2169 | {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf470 2170 | \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} 2171 | {\colortbl;\red255\green255\blue255;} 2172 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural 2173 | 2174 | \f0\fs24 \cf0 kubelet} 2175 | 2176 | 2177 | 2178 | Bounds 2179 | {{485.88813781738281, 388}, {88, 28}} 2180 | Class 2181 | ShapedGraphic 2182 | ID 2183 | 23 2184 | Layer 2185 | 8 2186 | Shape 2187 | RoundRect 2188 | Style 2189 | 2190 | Text 2191 | 2192 | Align 2193 | 0 2194 | Text 2195 | {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf470 2196 | \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} 2197 | {\colortbl;\red255\green255\blue255;} 2198 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural 2199 | 2200 | \f0\fs24 \cf0 kube-proxy} 2201 | 2202 | 2203 | 2204 | Bounds 2205 | {{21.5, 425}, {112, 28}} 2206 | Class 2207 | ShapedGraphic 2208 | ID 2209 | 17 2210 | Layer 2211 | 8 2212 | Shape 2213 | RoundRect 2214 | Style 2215 | 2216 | Text 2217 | 2218 | Align 2219 | 0 2220 | Text 2221 | {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf470 2222 | \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} 2223 | {\colortbl;\red255\green255\blue255;} 2224 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural 2225 | 2226 | \f0\fs24 \cf0 kube-apiserver} 2227 | 2228 | 2229 | 2230 | Bounds 2231 | {{247, 388}, {63, 28}} 2232 | Class 2233 | ShapedGraphic 2234 | ID 2235 | 22 2236 | Layer 2237 | 8 2238 | Shape 2239 | RoundRect 2240 | Style 2241 | 2242 | Text 2243 | 2244 | Align 2245 | 0 2246 | Text 2247 | {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf470 2248 | \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} 2249 | {\colortbl;\red255\green255\blue255;} 2250 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural 2251 | 2252 | \f0\fs24 \cf0 kubelet} 2253 | 2254 | 2255 | 2256 | Bounds 2257 | {{317.38812255859375, 388}, {88, 28}} 2258 | Class 2259 | ShapedGraphic 2260 | ID 2261 | 21 2262 | Layer 2263 | 8 2264 | Shape 2265 | RoundRect 2266 | Style 2267 | 2268 | Text 2269 | 2270 | Align 2271 | 0 2272 | Text 2273 | {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf470 2274 | \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} 2275 | {\colortbl;\red255\green255\blue255;} 2276 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural 2277 | 2278 | \f0\fs24 \cf0 kube-proxy} 2279 | 2280 | 2281 | 2282 | Bounds 2283 | {{61.694076538085938, 446}, {81, 28}} 2284 | Class 2285 | ShapedGraphic 2286 | ID 2287 | 20 2288 | Layer 2289 | 8 2290 | Shape 2291 | RoundRect 2292 | Style 2293 | 2294 | Text 2295 | 2296 | Align 2297 | 0 2298 | Text 2299 | {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf470 2300 | \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} 2301 | {\colortbl;\red255\green255\blue255;} 2302 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural 2303 | 2304 | \f0\fs24 \cf0 scheduler} 2305 | 2306 | 2307 | 2308 | Bounds 2309 | {{79, 467}, {76, 28}} 2310 | Class 2311 | ShapedGraphic 2312 | ID 2313 | 18 2314 | Layer 2315 | 8 2316 | Shape 2317 | RoundRect 2318 | Style 2319 | 2320 | Text 2321 | 2322 | Align 2323 | 0 2324 | Text 2325 | {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf470 2326 | \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} 2327 | {\colortbl;\red255\green255\blue255;} 2328 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural 2329 | 2330 | \f0\fs24 \cf0 controller} 2331 | 2332 | 2333 | 2334 | Bounds 2335 | {{21, 425}, {158.38815307617188, 107}} 2336 | Class 2337 | ShapedGraphic 2338 | ID 2339 | 11 2340 | Layer 2341 | 9 2342 | Shape 2343 | Rectangle 2344 | Text 2345 | 2346 | Text 2347 | {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf470 2348 | \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} 2349 | {\colortbl;\red255\green255\blue255;} 2350 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc 2351 | 2352 | \f0\b\fs32 \cf0 \ 2353 | \ 2354 | \ 2355 | \ 2356 | Master} 2357 | 2358 | 2359 | 2360 | Bounds 2361 | {{584, 388}, {158.38815307617188, 144}} 2362 | Class 2363 | ShapedGraphic 2364 | ID 2365 | 10 2366 | Layer 2367 | 9 2368 | Shape 2369 | Rectangle 2370 | Text 2371 | 2372 | Text 2373 | {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf470 2374 | \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} 2375 | {\colortbl;\red255\green255\blue255;} 2376 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc 2377 | 2378 | \f0\b\fs32 \cf0 \ 2379 | \ 2380 | \ 2381 | \ 2382 | \ 2383 | \ 2384 | Node} 2385 | 2386 | 2387 | 2388 | Bounds 2389 | {{415.49998474121094, 388}, {158.38815307617188, 144}} 2390 | Class 2391 | ShapedGraphic 2392 | ID 2393 | 6 2394 | Layer 2395 | 9 2396 | Shape 2397 | Rectangle 2398 | Text 2399 | 2400 | Text 2401 | {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf470 2402 | \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} 2403 | {\colortbl;\red255\green255\blue255;} 2404 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc 2405 | 2406 | \f0\b\fs32 \cf0 \ 2407 | \ 2408 | \ 2409 | \ 2410 | \ 2411 | \ 2412 | Node} 2413 | 2414 | 2415 | 2416 | Bounds 2417 | {{247, 388}, {158.38815307617188, 144}} 2418 | Class 2419 | ShapedGraphic 2420 | ID 2421 | 3 2422 | Layer 2423 | 9 2424 | Shape 2425 | Rectangle 2426 | Text 2427 | 2428 | Text 2429 | {\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf470 2430 | \cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} 2431 | {\colortbl;\red255\green255\blue255;} 2432 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc 2433 | 2434 | \f0\b\fs32 \cf0 \ 2435 | \ 2436 | \ 2437 | \ 2438 | \ 2439 | \ 2440 | Node} 2441 | 2442 | 2443 | 2444 | GridInfo 2445 | 2446 | GuidesLocked 2447 | NO 2448 | GuidesVisible 2449 | YES 2450 | HPages 2451 | 1 2452 | ImageCounter 2453 | 1 2454 | KeepToScale 2455 | 2456 | Layers 2457 | 2458 | 2459 | Lock 2460 | YES 2461 | Name 2462 | ingress connected 2463 | Print 2464 | YES 2465 | View 2466 | YES 2467 | 2468 | 2469 | Lock 2470 | YES 2471 | Name 2472 | Ingress 2473 | Print 2474 | NO 2475 | View 2476 | YES 2477 | 2478 | 2479 | Lock 2480 | YES 2481 | Name 2482 | direct (hide me) 2483 | Print 2484 | YES 2485 | View 2486 | NO 2487 | 2488 | 2489 | Lock 2490 | NO 2491 | Name 2492 | Services 2493 | Print 2494 | YES 2495 | View 2496 | YES 2497 | 2498 | 2499 | Lock 2500 | YES 2501 | Name 2502 | Label/Selector 2503 | Print 2504 | YES 2505 | View 2506 | YES 2507 | 2508 | 2509 | Lock 2510 | YES 2511 | Name 2512 | Deployment 2513 | Print 2514 | YES 2515 | View 2516 | YES 2517 | 2518 | 2519 | Lock 2520 | YES 2521 | Name 2522 | Replica 2523 | Print 2524 | YES 2525 | View 2526 | YES 2527 | 2528 | 2529 | Lock 2530 | YES 2531 | Name 2532 | Pods 2533 | Print 2534 | YES 2535 | View 2536 | YES 2537 | 2538 | 2539 | Lock 2540 | YES 2541 | Name 2542 | kube* 2543 | Print 2544 | YES 2545 | View 2546 | YES 2547 | 2548 | 2549 | Lock 2550 | YES 2551 | Name 2552 | Cluster 2553 | Print 2554 | YES 2555 | View 2556 | YES 2557 | 2558 | 2559 | LayoutInfo 2560 | 2561 | Animate 2562 | NO 2563 | circoMinDist 2564 | 18 2565 | circoSeparation 2566 | 0.0 2567 | layoutEngine 2568 | dot 2569 | neatoSeparation 2570 | 0.0 2571 | twopiSeparation 2572 | 0.0 2573 | 2574 | LinksVisible 2575 | NO 2576 | MagnetsVisible 2577 | NO 2578 | MasterSheets 2579 | 2580 | ModificationDate 2581 | 2017-04-25 20:48:38 +0000 2582 | Modifier 2583 | Jacob 2584 | NotesVisible 2585 | NO 2586 | Orientation 2587 | 2 2588 | OriginVisible 2589 | NO 2590 | PageBreaks 2591 | YES 2592 | PrintInfo 2593 | 2594 | NSBottomMargin 2595 | 2596 | float 2597 | 41 2598 | 2599 | NSHorizonalPagination 2600 | 2601 | coded 2602 | BAtzdHJlYW10eXBlZIHoA4QBQISEhAhOU051bWJlcgCEhAdOU1ZhbHVlAISECE5TT2JqZWN0AIWEASqEhAFxlwCG 2603 | 2604 | NSLeftMargin 2605 | 2606 | float 2607 | 18 2608 | 2609 | NSOrientation 2610 | 2611 | coded 2612 | BAtzdHJlYW10eXBlZIHoA4QBQISEhAhOU051bWJlcgCEhAdOU1ZhbHVlAISECE5TT2JqZWN0AIWEASqEhAFxlwGG 2613 | 2614 | NSPaperSize 2615 | 2616 | size 2617 | {792, 612} 2618 | 2619 | NSPrintReverseOrientation 2620 | 2621 | int 2622 | 0 2623 | 2624 | NSRightMargin 2625 | 2626 | float 2627 | 18 2628 | 2629 | NSTopMargin 2630 | 2631 | float 2632 | 18 2633 | 2634 | 2635 | PrintOnePage 2636 | 2637 | ReadOnly 2638 | NO 2639 | RowAlign 2640 | 1 2641 | RowSpacing 2642 | 36 2643 | SheetTitle 2644 | Canvas 1 2645 | SmartAlignmentGuidesActive 2646 | YES 2647 | SmartDistanceGuidesActive 2648 | YES 2649 | UniqueID 2650 | 1 2651 | UseEntirePage 2652 | 2653 | VPages 2654 | 1 2655 | WindowInfo 2656 | 2657 | CurrentSheet 2658 | 0 2659 | ExpandedCanvases 2660 | 2661 | 2662 | name 2663 | Canvas 1 2664 | 2665 | 2666 | Frame 2667 | {{1461, 166}, {993, 711}} 2668 | ListView 2669 | 2670 | OutlineWidth 2671 | 142 2672 | RightSidebar 2673 | 2674 | ShowRuler 2675 | 2676 | Sidebar 2677 | 2678 | SidebarWidth 2679 | 145 2680 | VisibleRegion 2681 | {{-38, -8}, {832.5, 569}} 2682 | Zoom 2683 | 1 2684 | ZoomValues 2685 | 2686 | 2687 | Canvas 1 2688 | 1 2689 | 1.5 2690 | 2691 | 2692 | 2693 | 2694 | 2695 | -------------------------------------------------------------------------------- /k8s-manifests/01-db-storage-class.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: storage.k8s.io/v1beta1 2 | kind: StorageClass 3 | metadata: 4 | name: pg-pv 5 | provisioner: kubernetes.io/aws-ebs 6 | # parameters: 7 | # # Select from io1, gp2, sc1, st1. The default is gp2 8 | # type: gp2 9 | # # AWS zone. If not specified, the zone matching the master is used 10 | # zone: us-east-1d 11 | # # Only for io1 volumes. I/O operations per second per GiB. The AWS volume plug-in 12 | # # multiplies this with the size of the requested volume to compute IOPS of the volume. 13 | # # The value cap is 20,000 IOPS, which is the maximum supported by AWS. See AWS 14 | # # documentation for further details. 15 | # iopsPerGB: "10" 16 | # # Denotes whether to encrypt the EBS volume 17 | # encrypted: true 18 | # # (optional) The full Amazon Resource Name (ARN) of the key to use 19 | # # when encrypting the volume. If none is supplied but encrypted is true, AWS generates a key 20 | # kmsKeyId: keyvalue 21 | -------------------------------------------------------------------------------- /k8s-manifests/02-db-volume-claim.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: PersistentVolumeClaim 3 | metadata: 4 | name: pg-pv-claim 5 | annotations: 6 | volume.beta.kubernetes.io/storage-class: pg-pv 7 | spec: 8 | accessModes: 9 | - ReadWriteOnce #this is just what we always do on AWS... 10 | resources: 11 | requests: 12 | storage: 20Gi 13 | -------------------------------------------------------------------------------- /k8s-manifests/03-db-secret.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Secret 3 | metadata: 4 | name: pg-db-secret 5 | type: Opaque 6 | data: 7 | postgres-password: <%= Base64.encode64(SecureRandom.hex(20)).gsub("\n","") %> 8 | -------------------------------------------------------------------------------- /k8s-manifests/04-db-deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: extensions/v1beta1 2 | kind: Deployment 3 | metadata: 4 | name: pg-for-pg-rails 5 | labels: 6 | app: pg-for-pg-rails #labels for the deployment 7 | spec: 8 | strategy: 9 | type: Recreate 10 | template: 11 | metadata: 12 | labels: #labels for the pods that will be created 13 | app: pg-for-pg-rails 14 | spec: 15 | containers: 16 | - image: postgres:9 17 | name: postgres #required field but seems kinda useless if we don't have multiple containers in a pod 18 | env: 19 | - name: POSTGRES_USER 20 | value: postgres 21 | # Required for pg_isready in the health probes. 22 | - name: PGUSER 23 | value: postgres 24 | - name: POSTGRES_DB 25 | value: "" 26 | - name: PGDATA 27 | value: /var/lib/postgresql/data/pgdata 28 | - name: POSTGRES_PASSWORD 29 | valueFrom: 30 | secretKeyRef: 31 | name: pg-db-secret 32 | key: postgres-password 33 | ports: 34 | - name: postgresql 35 | containerPort: 5432 36 | volumeMounts: 37 | - name: pg-volume-mount-name 38 | mountPath: /var/lib/postgresql/data 39 | volumes: 40 | - name: pg-volume-mount-name 41 | persistentVolumeClaim: 42 | claimName: pg-pv-claim 43 | -------------------------------------------------------------------------------- /k8s-manifests/05-db-service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: pg-rails-service 5 | labels: 6 | app: pg-for-pg-rails #this label doesn't matter as much as the selector label, but it's useful for operators 7 | spec: 8 | ports: 9 | - port: 3306 10 | selector: 11 | app: pg-for-pg-rails 12 | clusterIP: None 13 | -------------------------------------------------------------------------------- /k8s-manifests/06-rails-app.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: extensions/v1beta1 2 | kind: Deployment 3 | metadata: 4 | name: pg-rails 5 | labels: 6 | app: pg-rails 7 | spec: 8 | strategy: 9 | type: Recreate 10 | template: 11 | metadata: 12 | labels: 13 | app: pg-rails 14 | spec: 15 | containers: 16 | - name: pg-rails 17 | image: jacobo/pg-rails:latest 18 | env: 19 | - name: SECRET_KEY_BASE 20 | value: TODO 21 | - name: MY_APP_VERSION 22 | value: v1 #increment this to "cheat" and get a re-deployment 23 | - name: DB_HOST 24 | value: pg-rails-service #works because of kubeDNS and the name we gave our DB deployments 25 | - name: DB_PASSWORD 26 | valueFrom: 27 | secretKeyRef: 28 | name: pg-db-secret 29 | key: postgres-password 30 | ports: 31 | - containerPort: 5000 32 | name: pg-rails #TODO: why do ports need names? 33 | --------------------------------------------------------------------------------