├── Chapter03 ├── cli-hello-world-storage.yml ├── cli-hello-world.yml └── html │ └── index.html ├── Chapter04 ├── hello-world │ ├── hello-name.py │ ├── hello.py │ └── test.py ├── serverless-event │ ├── .gitignore │ ├── handler.py │ ├── package.json │ └── serverless.yml └── twitter │ ├── requirements.txt │ └── tweet.py ├── Chapter05 ├── blog │ ├── blogcount.js │ └── split.js ├── hello-world │ ├── LICENSE │ └── src │ │ └── hello.js └── twitter │ └── twitter.yml ├── Chapter08 ├── guestbook │ ├── add.py │ ├── cleanup.sh │ ├── get.py │ ├── redis.yaml │ └── run.sh ├── slack │ └── kubeEventsSlack.js ├── weather │ └── weather.js └── whale │ └── whalesay.sh ├── Chapter10 └── oms-daemonset.yaml ├── LICENSE └── README.md /Chapter03/cli-hello-world-storage.yml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: cli-hello-world-storage 5 | spec: 6 | selector: 7 | app: cli-hello-world-storage 8 | type: NodePort 9 | ports: 10 | - protocol: TCP 11 | port: 9000 12 | targetPort: 80 13 | --- 14 | apiVersion: apps/v1beta1 15 | kind: Deployment 16 | metadata: 17 | name: cli-hello-world-storage 18 | labels: 19 | app: nginx 20 | spec: 21 | replicas: 1 22 | selector: 23 | matchLabels: 24 | app: cli-hello-world-storage 25 | template: 26 | metadata: 27 | labels: 28 | app: cli-hello-world-storage 29 | spec: 30 | volumes: 31 | - name: html 32 | hostPath: 33 | path: /data/html 34 | containers: 35 | - name: nginx 36 | image: nginx:latest 37 | ports: 38 | - containerPort: 80 39 | volumeMounts: 40 | - mountPath: /usr/share/nginx/html 41 | name: html -------------------------------------------------------------------------------- /Chapter03/cli-hello-world.yml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: cli-hello-world 5 | spec: 6 | selector: 7 | app: cli-hello-world 8 | type: NodePort 9 | ports: 10 | - protocol: TCP 11 | port: 8000 12 | targetPort: 80 13 | --- 14 | apiVersion: apps/v1beta1 15 | kind: Deployment 16 | metadata: 17 | name: cli-hello-world 18 | labels: 19 | app: nginx 20 | spec: 21 | replicas: 1 22 | selector: 23 | matchLabels: 24 | app: cli-hello-world 25 | template: 26 | metadata: 27 | labels: 28 | app: cli-hello-world 29 | spec: 30 | containers: 31 | - name: nginx 32 | image: nginx:latest 33 | ports: 34 | - containerPort: 80 -------------------------------------------------------------------------------- /Chapter03/html/index.html: -------------------------------------------------------------------------------- 1 | 2 | Hello from the host 3 | 11 | 12 |
13 |

Hello from the host !!!

14 |
15 |

This page is being served by mounting the html folder containing this index.html from your local machine into the Minikube virtual machine, from there is being mounted into the container running in your pod.

16 |
17 |
-------------------------------------------------------------------------------- /Chapter04/hello-world/hello-name.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | def handler(context): 4 | print context.json 5 | return context.json -------------------------------------------------------------------------------- /Chapter04/hello-world/hello.py: -------------------------------------------------------------------------------- 1 | import json 2 | def handler(): 3 | return "Hello World!" -------------------------------------------------------------------------------- /Chapter04/hello-world/test.py: -------------------------------------------------------------------------------- 1 | def foobar(context): 2 | print context.json 3 | return context.json -------------------------------------------------------------------------------- /Chapter04/serverless-event/.gitignore: -------------------------------------------------------------------------------- 1 | .serverless/ 2 | node_modules/ 3 | package-lock.json -------------------------------------------------------------------------------- /Chapter04/serverless-event/handler.py: -------------------------------------------------------------------------------- 1 | def events(context): 2 | return context 3 | -------------------------------------------------------------------------------- /Chapter04/serverless-event/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hello-events", 3 | "version": "1.0.0", 4 | "description": "Example function for serverless kubeless", 5 | "dependencies": { 6 | "serverless-kubeless": "^0.2.0" 7 | }, 8 | "devDependencies": {}, 9 | "scripts": { 10 | "test": "echo \"Error: no test specified\" && exit 1" 11 | }, 12 | "author": "", 13 | "license": "Apache-2.0" 14 | } 15 | -------------------------------------------------------------------------------- /Chapter04/serverless-event/serverless.yml: -------------------------------------------------------------------------------- 1 | service: events 2 | 3 | provider: 4 | name: kubeless 5 | runtime: python2.7 6 | 7 | plugins: 8 | - serverless-kubeless 9 | 10 | functions: 11 | events: 12 | handler: handler.events 13 | events: 14 | - trigger: 'hello_topic' 15 | -------------------------------------------------------------------------------- /Chapter04/twitter/requirements.txt: -------------------------------------------------------------------------------- 1 | python-twitter 2 | kubernetes==2.0.0 -------------------------------------------------------------------------------- /Chapter04/twitter/tweet.py: -------------------------------------------------------------------------------- 1 | import base64 2 | import twitter 3 | 4 | from kubernetes import client, config 5 | 6 | config.load_incluster_config() 7 | 8 | v1=client.CoreV1Api() 9 | 10 | for secrets in v1.list_secret_for_all_namespaces().items: 11 | if secrets.metadata.name == 'twitter': 12 | consumer_key = base64.b64decode(secrets.data['consumer_key']) 13 | consumer_secret = base64.b64decode(secrets.data['consumer_secret']) 14 | token_key = base64.b64decode(secrets.data['token_key']) 15 | token_secret = base64.b64decode(secrets.data['token_secret']) 16 | 17 | api = twitter.Api(consumer_key=consumer_key, 18 | consumer_secret=consumer_secret, 19 | access_token_key=token_key, 20 | access_token_secret=token_secret) 21 | 22 | def handler(context): 23 | msg = context.json 24 | status = api.PostUpdate(msg['tweet']) -------------------------------------------------------------------------------- /Chapter05/blog/blogcount.js: -------------------------------------------------------------------------------- 1 | module.exports = function(context, callback) { 2 | var body = context.request.body; 3 | body.titleWordCount = countWords(body.title); 4 | body.bodyWordCount = countWords(body.body); 5 | 6 | callback(200, JSON.stringify(body)); 7 | }; 8 | 9 | // 10 | function countWords(text) { 11 | var words = null; 12 | if (text) { 13 | words = text.split(" "); 14 | return words.length; 15 | } 16 | return 0; 17 | } -------------------------------------------------------------------------------- /Chapter05/blog/split.js: -------------------------------------------------------------------------------- 1 | module.exports = function (context, callback) { 2 | const http = require('http'); 3 | if (!http) { 4 | console.log("could not require http"); 5 | callback(400, "Could not require http"); 6 | return; 7 | } 8 | 9 | var body = context.request.body; 10 | if (body && body.constructor === Array) { 11 | var counter = 0; 12 | var result = { 13 | responses: [] 14 | }; 15 | var status = 200; 16 | var firstError = null; 17 | 18 | function returnError(e) { 19 | console.log("Caught error: " + e); 20 | result.error = e; 21 | status = 400; 22 | var resultJson = JSON.stringify(result); 23 | console.log("result: " + status + " " + resultJson); 24 | callback(status, resultJson); 25 | } 26 | 27 | try { 28 | var lastIndex = body.length - 1; 29 | body.forEach(function (item, idx) { 30 | var postData = JSON.stringify(item); 31 | var postOptions = { 32 | hostname: 'blogcount', 33 | port: '80', 34 | path: '/', 35 | method: 'POST', 36 | headers: { 37 | 'Content-Type': 'application/json', 38 | 'Cache-Control': 'no-cache', 39 | 'Content-Length': postData.length 40 | } 41 | }; 42 | 43 | req = http.request(postOptions, function (res) { 44 | result[idx] = { 45 | statusCode: res.statusCode 46 | }; 47 | res.setEncoding('utf8'); 48 | var data = ""; 49 | res.on('data', function (chunk) { 50 | data += chunk; 51 | }); 52 | res.on('end', function () { 53 | result[idx].response = data; 54 | if (idx === lastIndex) { 55 | result.count = counter; 56 | if (firstError) { 57 | console.log("Failed with error: " + firstError); 58 | results.error = firstError; 59 | status = 400; 60 | } 61 | var resultJson = JSON.stringify(result); 62 | callback(status, resultJson); 63 | } 64 | }); 65 | }); 66 | 67 | req.on('error', function (e) { 68 | console.log('problem with request: ' + e.message); 69 | if (idx === lastIndex) { 70 | returnError(e); 71 | } 72 | }); 73 | 74 | req.write(postData); 75 | req.end(); 76 | counter++; 77 | }); 78 | } catch (e) { 79 | returnError(e); 80 | } 81 | } else { 82 | callback(400, "No array is passed in. Was given: " + JSON.stringify(body)); 83 | } 84 | }; 85 | 86 | 87 | -------------------------------------------------------------------------------- /Chapter05/hello-world/LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /Chapter05/hello-world/src/hello.js: -------------------------------------------------------------------------------- 1 | module.exports = function(context, callback) { 2 | var name = context.request.query.name || context.request.body || "World"; 3 | callback(200, "Hello " + name + "!!"); 4 | }; -------------------------------------------------------------------------------- /Chapter05/twitter/twitter.yml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: "v1" 3 | kind: "ConfigMap" 4 | metadata: 5 | name: "flow-twitter" 6 | labels: 7 | funktion.fabric8.io/kind: "Flow" 8 | connector: "twitter" 9 | data: 10 | application.properties: | 11 | # spring application properties file 12 | # NOTE these secrets are purely for demos 13 | # please replace with your access token secrets for your apps!!! 14 | camel.component.twitter.access-token=2213091858-REJvMEEUeSoGA0WPKp7cv8BBTyTcDeRkHBr6Wpj 15 | camel.component.twitter.access-token-secret=WopER9tbSJtUtASEz62lI8HTCvhlYBvDHcuCIof5YzyGg 16 | camel.component.twitter.consumer-key=aKiWFB6Q7Ck5byHTWu3zHktDF 17 | camel.component.twitter.consumer-secret=uFPEszch9UuIlHt6nCxar8x1DSYqhWw8VELqp3pMPB571DwnDg 18 | funktion.yml: | 19 | --- 20 | flows: 21 | - logResult: true 22 | steps: 23 | - kind: endpoint 24 | uri: twitter://search?type=direct&keywords=Kubernetes -------------------------------------------------------------------------------- /Chapter08/guestbook/add.py: -------------------------------------------------------------------------------- 1 | # 2 | # Handles POST /guestbook -- adds item to guestbook 3 | # 4 | 5 | from flask import request, redirect 6 | import redis 7 | 8 | # Connect to redis. 9 | redisConnection = redis.StrictRedis(host='redis.guestbook', port=6379, db=0) 10 | 11 | def main(): 12 | # Read the item from POST params, add it to redis, and redirect 13 | # back to the list 14 | item = request.form['text'] 15 | redisConnection.rpush('guestbook', item) 16 | return redirect('/guestbook', code=303) 17 | -------------------------------------------------------------------------------- /Chapter08/guestbook/cleanup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | kubectl delete ns guestbook 4 | 5 | fission fn delete --name guestbook-add 6 | fission fn delete --name guestbook-get 7 | 8 | fission route list|grep guestbook|cut -f1 -d' '|xargs -n1 fission route delete --name 9 | -------------------------------------------------------------------------------- /Chapter08/guestbook/get.py: -------------------------------------------------------------------------------- 1 | # 2 | # Handles GET /guestbook -- returns a list of items in the guestbook 3 | # with a form to add more. 4 | # 5 | 6 | from flask import current_app, escape 7 | import redis 8 | 9 | # Connect to redis. This is run only when this file is loaded; as 10 | # long as the pod is alive, the connection is reused. 11 | redisConnection = redis.StrictRedis(host='redis.guestbook', port=6379, db=0) 12 | 13 | def main(): 14 | messages = redisConnection.lrange('guestbook', 0, -1) 15 | 16 | items = [("
  • %s
  • " % escape(m.decode('utf-8'))) for m in messages] 17 | ul = "" % "\n".join(items) 18 | return """ 19 | 20 |

    Guestbook

    21 |
    22 | 23 | 24 |
    25 |
    26 | %s 27 | 28 | """ % ul 29 | -------------------------------------------------------------------------------- /Chapter08/guestbook/redis.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Namespace 3 | metadata: 4 | name: guestbook 5 | labels: 6 | name: guestbook 7 | 8 | --- 9 | apiVersion: extensions/v1beta1 10 | kind: Deployment 11 | metadata: 12 | labels: 13 | run: redis 14 | name: redis 15 | namespace: guestbook 16 | spec: 17 | replicas: 1 18 | selector: 19 | matchLabels: 20 | run: redis 21 | template: 22 | metadata: 23 | labels: 24 | run: redis 25 | spec: 26 | containers: 27 | - image: redis 28 | name: redis 29 | 30 | --- 31 | apiVersion: v1 32 | kind: Service 33 | metadata: 34 | labels: 35 | run: redis 36 | name: redis 37 | namespace: guestbook 38 | spec: 39 | selector: 40 | run: redis 41 | type: ClusterIP 42 | ports: 43 | - port: 6379 44 | protocol: TCP 45 | targetPort: 6379 46 | -------------------------------------------------------------------------------- /Chapter08/guestbook/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | DEMO_RUN_FAST=1 4 | ROOT_DIR=$(dirname $0)/.. 5 | . $ROOT_DIR/util.sh 6 | 7 | desc "Deploy redis" 8 | run "kubectl create -f redis.yaml" 9 | 10 | desc "Ensure fission has a python environment" 11 | run "fission env create --name python --image fission/python-env" 12 | 13 | desc "Register fission functions" 14 | run "fission function create --name guestbook-get --env python --code get.py --url /guestbook --method GET" 15 | run "fission function create --name guestbook-add --env python --code add.py --url /guestbook --method POST" 16 | 17 | echo "http://$FISSION_ROUTER/guestbook" 18 | 19 | -------------------------------------------------------------------------------- /Chapter08/slack/kubeEventsSlack.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | let https = require('https'); 4 | 5 | const slackWebhookPath = "/put/your/url/here"; // Something like "/services/XXX/YYY/zZz123" 6 | 7 | function upcaseFirst(s) { 8 | return s.charAt(0).toUpperCase() + s.slice(1).toLowerCase(); 9 | } 10 | 11 | async function sendSlackMessage(msg) { 12 | let postData = `{"text": "${msg}"}`; 13 | let options = { 14 | hostname: "hooks.slack.com", 15 | path: slackWebhookPath, 16 | method: "POST", 17 | headers: { 18 | "Content-Type": "application/json" 19 | } 20 | }; 21 | 22 | return new Promise(function(resolve, reject) { 23 | let req = https.request(options, function(res) { 24 | console.log(`slack request status = ${res.statusCode}`); 25 | return resolve(); 26 | }); 27 | req.write(postData); 28 | req.end(); 29 | }); 30 | } 31 | 32 | module.exports = async function(context) { 33 | console.log(context.request.headers); 34 | 35 | let obj = context.request.body; 36 | let version = obj.metadata.resourceVersion; 37 | let eventType = context.request.get('X-Kubernetes-Event-Type'); 38 | let objType = context.request.get('X-Kubernetes-Object-Type'); 39 | 40 | let msg = `${upcaseFirst(eventType)} ${objType} ${obj.metadata.name}`; 41 | console.log(msg, version); 42 | 43 | if (eventType == 'DELETED' || eventType == 'ADDED') { 44 | console.log("sending event to slack") 45 | await sendSlackMessage(msg); 46 | } 47 | 48 | return { 49 | status: 200, 50 | body: "" 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Chapter08/weather/weather.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const rp = require('request-promise-native'); 4 | 5 | module.exports = async function (context) { 6 | const stringBody = JSON.stringify(context.request.body); 7 | const body = JSON.parse(stringBody); 8 | const location = body.location; 9 | 10 | if (!location) { 11 | return { 12 | status: 400, 13 | body: { 14 | text: 'You must provide a location.' 15 | } 16 | }; 17 | } 18 | 19 | try { 20 | const response = await rp(`https://query.yahooapis.com/v1/public/yql?q=select item.condition from weather.forecast where woeid in (select woeid from geo.places(1) where text="${location}") and u="c"&format=json`); 21 | const condition = JSON.parse(response).query.results.channel.item.condition; 22 | const text = condition.text; 23 | const temperature = condition.temp; 24 | return { 25 | status: 200, 26 | body: { 27 | text: `It is ${temperature} celsius degrees in ${location} and ${text}` 28 | }, 29 | headers: { 30 | 'Content-Type': 'application/json' 31 | } 32 | }; 33 | } catch (e) { 34 | console.error(e); 35 | return { 36 | status: 500, 37 | body: e 38 | }; 39 | } 40 | } -------------------------------------------------------------------------------- /Chapter08/whale/whalesay.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if ! hash cowsay 2> /dev/null; then 4 | apk update > /dev/null 5 | apk add curl perl > /dev/null 6 | curl https://raw.githubusercontent.com/docker/whalesay/master/cowsay > /bin/cowsay 2> /dev/null 7 | chmod +x /bin/cowsay 8 | mkdir -p /usr/local/share/cows/ 9 | curl https://raw.githubusercontent.com/docker/whalesay/master/docker.cow > /usr/local/share/cows/default.cow 2> /dev/null 10 | fi 11 | 12 | cowsay 13 | -------------------------------------------------------------------------------- /Chapter10/oms-daemonset.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: extensions/v1beta1 2 | kind: DaemonSet 3 | metadata: 4 | name: omsagent 5 | spec: 6 | template: 7 | metadata: 8 | labels: 9 | app: omsagent 10 | agentVersion: 1.4.0-12 11 | dockerProviderVersion: 10.0.0-25 12 | spec: 13 | containers: 14 | - name: omsagent 15 | image: "microsoft/oms" 16 | imagePullPolicy: Always 17 | env: 18 | - name: WSID 19 | value: "" 20 | - name: KEY 21 | value: "" 22 | securityContext: 23 | privileged: true 24 | ports: 25 | - containerPort: 25225 26 | protocol: TCP 27 | - containerPort: 25224 28 | protocol: UDP 29 | volumeMounts: 30 | - mountPath: /var/run/docker.sock 31 | name: docker-sock 32 | - mountPath: /var/opt/microsoft/omsagent/state/containerhostname 33 | name: container-hostname 34 | - mountPath: /var/log 35 | name: host-log 36 | - mountPath: /var/lib/docker/containers/ 37 | name: container-log 38 | livenessProbe: 39 | exec: 40 | command: 41 | - /bin/bash 42 | - -c 43 | - ps -ef | grep omsagent | grep -v "grep" 44 | initialDelaySeconds: 60 45 | periodSeconds: 60 46 | nodeSelector: 47 | beta.kubernetes.io/os: linux 48 | # Tolerate a NoSchedule taint on master that ACS Engine sets. 49 | tolerations: 50 | - key: "node-role.kubernetes.io/master" 51 | operator: "Equal" 52 | value: "true" 53 | effect: "NoSchedule" 54 | volumes: 55 | - name: docker-sock 56 | hostPath: 57 | path: /var/run/docker.sock 58 | - name: container-hostname 59 | hostPath: 60 | path: /etc/hostname 61 | - name: host-log 62 | hostPath: 63 | path: /var/log 64 | - name: container-log 65 | hostPath: 66 | path: /var/lib/docker/containers/ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Packt 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | # Kubernetes for Serverless Applications 5 | This is the code repository for [Kubernetes for Serverless Applications](https://www.packtpub.com/networking-and-servers/kubernetes-serverless-applications?utm_source=github&utm_medium=repository&utm_campaign=9781788620376), published by [Packt](https://www.packtpub.com/?utm_source=github). It contains all the supporting project files necessary to work through the book from start to finish. 6 | ## About the Book 7 | Kubernetes is often documented and approached from the perspective of someone just running software already built. Kubernetes may also be used to enhance the development process itself, enabling more consistent testing and analysis of written code so that developers can verify not only correctness, but efficiency as well. This book will introduce the key concepts of Kubernetes, linked with examples of how to deploy and use those with a bit of NodeJS and Python example code, so that a reader could quickly replicate and use that knowledge themselves in their development process. 8 | 9 | You will begin by setting up Kubernetes for development and packaging your code to run in Kubernetes. It will walk you through the set up and installation process before working with Kubernetes in the development environment. We will then take a deep dive into concepts like automating your build process, autonomic computing, debugging, integration testing and so on. This book will cover all the necessary concepts required for any developer to work with Kubernetes. Towards the end of this book, we will be covering few security best practices which will secure the developer environment. By the end of this book, you will be in a position to use Kubernetes in the development ecosystem. 10 | ## Instructions and Navigation 11 | All of the code is organized into folders. For example, Chapter03. 12 | 13 | 14 | 15 | The code will look like the following: 16 | ``` 17 | apiVersion: apps/v1beta1 18 | 19 | kind: Deployment 20 | 21 | metadata: 22 | 23 | name: cli-hello-world 24 | 25 | labels: 26 | 27 | app: nginx 28 | ``` 29 | 30 | Operating Systems: 31 | * macOS High Sierra 32 | * Ubuntu 17.04 33 | * Windows 10 Professional 34 | 35 | Software: 36 | We will be installing several command-line tools throughout this book; each of the tools will have installation instructions and details of its requirements in the chapters. Note that while instructions for Windows systems are provided, a lot of the tools we will be using 37 | were originally designed to run primarily on Linux/Unix based systems such as Ubuntu 17.04 and macOS High Sierra, and the book will favor these systems. While every effort has been made at the time of writing to verify that the tools work on Windows-based systems, 38 | as some of the tools are experimental builds, we cannot guarantee that they will continue to work on updated systems, because of this, I would recommend using either a Linux- or Unix-based system. 39 | 40 | Hardware: 41 | * Windows 10 Professional and Ubuntu 17.04 system requirements: 42 | * Systems using processors (CPUs) launched in 2011 or later with a 1.3 GHz or faster core speed, except Intel Atom processors or AMD processors based on the Llano and Bobcat micro-architectures. 4 GB RAM minimum with 8 GB RAM or more recommended 43 | * Apple Mac system requirements: 44 | * iMac: Late 2009 or newer 45 | * MacBook/MacBook (Retina): Late 2009 or newer 46 | * MacBook Pro: Mid-2010 or newer 47 | * MacBook Air: Late 2010 or newer 48 | * Mac mini: Mid-2010 or newer 49 | * Mac Pro: Mid-2010 or newer 50 | * Access to at least one of the following public cloud services: 51 | * [AWS](https://aws.amazon.com/) 52 | * [Google Cloud](https://cloud.google.com/) 53 | * [Microsoft Azure](https://azure.microsoft.com/) 54 | * [DigitalOcean](https://www.digitalocean.com/) 55 | 56 | ## Related Products 57 | * [Getting Started with Kubernetes](https://www.packtpub.com/virtualization-and-cloud/getting-started-kubernetes?utm_source=github&utm_medium=repository&utm_campaign=9781784394035) 58 | 59 | * [DevOps with Kubernetes](https://www.packtpub.com/virtualization-and-cloud/devops-kubernetes?utm_source=github&utm_medium=repository&utm_campaign=9781788396646) 60 | 61 | * [Introduction to Kubernetes using Docker [Video]](https://www.packtpub.com/virtualization-and-cloud/introduction-kubernetes-using-docker-video?utm_source=github&utm_medium=repository&utm_campaign=9781788998000) 62 | ### Download a free PDF 63 | 64 | If you have already purchased a print or Kindle version of this book, you can get a DRM-free PDF version at no cost.
    Simply click on the link to download a free PDF copy of this book.
    65 |

    https://packt.link/free-ebook/9781788620376

    --------------------------------------------------------------------------------