|
| 1 | +--- |
| 2 | +title: Code to Kubernetes - Python |
| 3 | +linkTitle: Code to Kubernetes |
| 4 | +weight: 4 |
| 5 | +--- |
| 6 | + |
| 7 | +## Code to Kubernetes - Python |
| 8 | + |
| 9 | +**Objective:** Understand activities to instrument a python application and run it on Kubernetes. |
| 10 | + |
| 11 | +- Verify the code |
| 12 | +- Containerize the app |
| 13 | +- Deploy the container in Kubernetes |
| 14 | + |
| 15 | +**Note:** these steps do not involve Splunk |
| 16 | + |
| 17 | +**Duration:** 15 Minutes |
| 18 | + |
| 19 | +## Verify the code - Review service |
| 20 | + |
| 21 | +Inspect review.py (workshop/flask_apps_start/review) |
| 22 | + |
| 23 | +``` python |
| 24 | +from flask import Flask, jsonify |
| 25 | +import random |
| 26 | +import subprocess |
| 27 | + |
| 28 | +review = Flask(__name__) |
| 29 | +num_reviews = 8635403 |
| 30 | +num_reviews = 100000 |
| 31 | +reviews_file = '/var/appdata/yelp_academic_dataset_review.json' |
| 32 | + |
| 33 | +@review.route('/') |
| 34 | +def hello_world(): |
| 35 | + return jsonify(message='Hello, you want to hit /get_review. We have ' + str(num_reviews) + ' reviews!') |
| 36 | + |
| 37 | +@review.route('/get_review') |
| 38 | +def get_review(): |
| 39 | + random_review_int = str(random.randint(1,num_reviews)) |
| 40 | + line_num = random_review_int + 'q;d' |
| 41 | + command = ["sed", line_num, reviews_file] # sed "7997242q;d" <file> |
| 42 | + random_review = subprocess.run(command, stdout=subprocess.PIPE, text=True) |
| 43 | + return random_review.stdout |
| 44 | + |
| 45 | +if __name__ == "__main__": |
| 46 | + review.run(host ='0.0.0.0', port = 5000, debug = True) |
| 47 | +``` |
| 48 | + |
| 49 | +Inspect requirements.txt |
| 50 | + |
| 51 | +``` text |
| 52 | +Flask==2.0.2 |
| 53 | +``` |
| 54 | + |
| 55 | +Create a virtual environment and Install the necessary python packages |
| 56 | + |
| 57 | +``` bash |
| 58 | +cd Workshop/flask_apps_start/review |
| 59 | + |
| 60 | +python3 -m venv rtapp-workshop |
| 61 | +source rtapp-workshop/bin/activate |
| 62 | + |
| 63 | +pip freeze #note output |
| 64 | +pip install -r requirements.txt |
| 65 | +pip freeze #note output |
| 66 | +``` |
| 67 | + |
| 68 | +Start the REVIEW service. **Note:** You can stop the app with control+C |
| 69 | + |
| 70 | +``` bash |
| 71 | +python3 review.py |
| 72 | + |
| 73 | + * Serving Flask app 'review' (lazy loading) |
| 74 | + * Environment: production |
| 75 | + ...snip... |
| 76 | + * Running on http://10.160.145.246:5000/ (Press CTRL+C to quit) |
| 77 | + * Restarting with stat |
| 78 | +127.0.0.1 - - [17/May/2022 22:46:38] "GET / HTTP/1.1" 200 - |
| 79 | +127.0.0.1 - - [17/May/2022 22:47:02] "GET /get_review HTTP/1.1" 200 - |
| 80 | +127.0.0.1 - - [17/May/2022 22:47:58] "GET /get_review HTTP/1.1" 200 - |
| 81 | +``` |
| 82 | + |
| 83 | +Verify that the service is working |
| 84 | +- Hit the URL http://localhost:5000 and http://localhost:5000/get_review with a browser |
| 85 | +- Or, use curl in your terminal |
| 86 | + |
| 87 | +``` bash |
| 88 | +curl localhost:5000 |
| 89 | +{ |
| 90 | + "message": "Hello, you want to hit /get_review. We have 100000 reviews!" |
| 91 | +} |
| 92 | + |
| 93 | +curl localhost:5000/get_review |
| 94 | +{"review_id":"NjbiESXotcEdsyTc4EM3fg","user_id":"PR9LAM19rCM_HQiEm5OP5w","business_id":"UAtX7xmIfdd1W2Pebf6NWg","stars":3.0,"useful":0,"funny":0,"cool":0,"text":"-If you're into cheap beer (pitcher of bud-light for $7) decent wings and a good time, this is the place for you. Its generally very packed after work hours and weekends. Don't expect cocktails. \n\n-You run into a lot of sketchy characters here sometimes but for the most part if you're chilling with friends its not that bad. \n\n-Friendly bouncer and bartenders.","date":"2016-04-12 20:23:24"} |
| 95 | +``` |
| 96 | + |
| 97 | +{{% alert title="Workshop Question" color="danger" %}} |
| 98 | + |
| 99 | +- What does this application do? |
| 100 | +- Do you see the yelp dataset being used? |
| 101 | +- Why did the output of pip freeze differ each time you ran it? |
| 102 | +- Which port is the REVIEW app listening on? Can other python apps use this same port? |
| 103 | + |
| 104 | +{{% /alert %}}} |
| 105 | + |
| 106 | +## Create a REVIEW container |
| 107 | + |
| 108 | +To create a container image, you need to create a Dockerfile, run docker build to build the image referencing the Docker file and push it up to a remote repository so it can be pulled by other sources. |
| 109 | + |
| 110 | +- Create a Dockerfile |
| 111 | +- Creating a Dockerfile typically requires you to consider the following: |
| 112 | + - Identify an appropriate container image |
| 113 | + - ubuntu vs. python vs. alpine/slim |
| 114 | + - ubuntu - overkill, large image size, wasted resources when running in K8 |
| 115 | + - this is a python app, so pick an image that is optimized for it |
| 116 | + - avoid alpine for python |
| 117 | + - Order matters |
| 118 | + - you're building layers. |
| 119 | + - re-use the layers as much as possible |
| 120 | + - have items that change often towards the end |
| 121 | + - Other Best practices for writing Dockerfiles |
| 122 | + |
| 123 | +Dockerfile for review |
| 124 | + |
| 125 | +``` dockerfile |
| 126 | +FROM python:3.10-slim |
| 127 | +WORKDIR /app |
| 128 | +COPY requirements.txt /app |
| 129 | +RUN pip install -r requirements.txt |
| 130 | +COPY ./review.py /app |
| 131 | +EXPOSE 5000 |
| 132 | +CMD [ "python", "review.py" ] |
| 133 | +``` |
| 134 | + |
| 135 | +Create a container image (locally) |
| 136 | +Run ‘docker build’ to build a local container image referencing the Dockerfile |
| 137 | + |
| 138 | +``` bash |
| 139 | +(venv)% docker build -f Dockerfile -t localhost:8000/review:0.01 . |
| 140 | +[+] Building 35.5s (11/11) FINISHED |
| 141 | + => [internal] load build definition from Dockerfile 0.0s |
| 142 | + ...snip... |
| 143 | + => [3/5] COPY requirements.txt /app 0.0s |
| 144 | + => [4/5] RUN pip install -r requirements.txt 4.6s |
| 145 | + => [5/5] COPY ./review.py /app 0.0s |
| 146 | + => exporting to image 0.2s |
| 147 | + => => exporting layers 0.2s |
| 148 | + => => writing image sha256:61da27081372723363d0425e0ceb34bbad6e483e698c6fe439c5 0.0s |
| 149 | + => => naming to docker.io/localhost:8000/review:0.1 0.0 |
| 150 | +``` |
| 151 | + |
| 152 | +Push the container image into a container repository |
| 153 | +Run ‘docker push’ to place a copy of the REVIEW container to a remote location |
| 154 | + |
| 155 | +``` bash |
| 156 | +docker push localhost:8000/review:0.01 |
| 157 | +The push refers to repository [docker.io/localhost:8000/review] |
| 158 | +02c36dfb4867: Pushed |
| 159 | + ...snip... |
| 160 | +fd95118eade9: Pushed |
| 161 | +0.1: digest: sha256:3651f740abe5635af95d07acd6bcf814e4d025fcc1d9e4af9dee023a9b286f38 size: 2202 |
| 162 | +``` |
| 163 | + |
| 164 | +Verify that the image is in Docker Hub. The same info can be found in Docker Desktop |
| 165 | + |
| 166 | +``` bash |
| 167 | +curl -s http://localhost:8000/v2/_catalog |
| 168 | +{"repositories":["review"]} |
| 169 | +``` |
| 170 | + |
| 171 | +## Run REVIEW in Kubernetes |
| 172 | + |
| 173 | +Create K8 deployment yaml file for the REVIEW app |
| 174 | +Reference: Creating a Deployment |
| 175 | + |
| 176 | +review.deployment.yaml |
| 177 | + |
| 178 | +``` yaml |
| 179 | +apiVersion: apps/v1 |
| 180 | +kind: Deployment |
| 181 | +metadata: |
| 182 | + name: review |
| 183 | + labels: |
| 184 | + app: review |
| 185 | +spec: |
| 186 | + replicas: 1 |
| 187 | + selector: |
| 188 | + matchLabels: |
| 189 | + app: review |
| 190 | + template: |
| 191 | + metadata: |
| 192 | + labels: |
| 193 | + app: review |
| 194 | + spec: |
| 195 | + imagePullSecrets: |
| 196 | + - name: regcred |
| 197 | + containers: |
| 198 | + - image: localhost:8000/review:0.01 |
| 199 | + name: review |
| 200 | + volumeMounts: |
| 201 | + - mountPath: /var/appdata |
| 202 | + name: appdata |
| 203 | + volumes: |
| 204 | + - name: appdata |
| 205 | + hostPath: |
| 206 | + path: /var/appdata |
| 207 | +``` |
| 208 | +
|
| 209 | +Notes regarding review.deployment.yaml: |
| 210 | +
|
| 211 | +- labels - K8 uses labels and selectors to tag and identify resources |
| 212 | + - In the next step, we'll create a service and associate it to this deployment using the label |
| 213 | +- replicas = 1 |
| 214 | + - K8 allows you to scale your deployments horizontally |
| 215 | + - We'll leverage this later to add load and increase our ingestion rate |
| 216 | +- regcred provides this deployment with the ability to access your dockerhub credentials which is necessary to pull the container image. |
| 217 | +- The volume definition and volumemount make the yelp dataset visible to the container |
| 218 | +
|
| 219 | +Create a K8 service yaml file for the review app. Reference: Creating a service: |
| 220 | +
|
| 221 | +review.service.yaml |
| 222 | +
|
| 223 | +``` yaml |
| 224 | +apiVersion: v1 |
| 225 | +kind: Service |
| 226 | +metadata: |
| 227 | + name: review |
| 228 | +spec: |
| 229 | + type: NodePort |
| 230 | + selector: |
| 231 | + app: review |
| 232 | + ports: |
| 233 | + - port: 5000 |
| 234 | + targetPort: 5000 |
| 235 | + nodePort: 30000 |
| 236 | +``` |
| 237 | +
|
| 238 | +Notes about review.service.yaml: |
| 239 | +
|
| 240 | +- the selector associates this service to pods with the label app with the value being review |
| 241 | +- the review service exposes the review pods as a network service |
| 242 | + - other pods can now ping 'review' and they will hit a review pod. |
| 243 | + - a pod would get a review if it ran 'curl http://review:5000' |
| 244 | +- NodePort service |
| 245 | + - the service is accessible to the K8 host by the nodePort, 30000 |
| 246 | + - Another machine that has this can get a review if it ran 'curl http://<k8 host ip>:30000' |
| 247 | +
|
| 248 | +Apply the review deployment and service |
| 249 | +
|
| 250 | +``` bash |
| 251 | +kubectl apply -f review.service.yaml -f review.deployment.yaml |
| 252 | +``` |
| 253 | + |
| 254 | +Verify that the deployment and services are running: |
| 255 | + |
| 256 | +``` text |
| 257 | +ubuntu@ip-10-0-1-54:/tmp$ kubectl get deployments |
| 258 | +NAME READY UP-TO-DATE AVAILABLE AGE |
| 259 | +review 1/1 1 1 19h |
| 260 | +
|
| 261 | +ubuntu@ip-10-0-1-54:/tmp$ kubectl get services |
| 262 | +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE |
| 263 | +review NodePort 10.43.175.21 <none> 5000:30000/TCP 154d |
| 264 | +
|
| 265 | +ubuntu@ip-10-0-1-54:/tmp$ curl localhost:30000 |
| 266 | +{ |
| 267 | + "message": "Hello, you want to hit /get_review. We have 100000 reviews!" |
| 268 | +} |
| 269 | +ubuntu@ip-10-0-1-54:/tmp$ curl localhost:30000/get_review |
| 270 | +{"review_id":"Vv9rHtfBrFc-1M1DHRKN9Q","user_id":"EaNqIwKkM7p1bkraKotqrg","business_id":"TA1KUSCu8GkWP9w0rmElxw","stars":3.0,"useful":1,"funny":0,"cool":0,"text":"This is the first time I've actually written a review for Flip, but I've probably been here about 10 times. \n\nThis used to be where I would take out of town guests who wanted a good, casual, and relatively inexpensive meal. \n\nI hadn't been for a while, so after a long day in midtown, we decided to head to Flip. \n\nWe had the fried pickles, onion rings, the gyro burger, their special burger, and split a nutella milkshake. I have tasted all of the items we ordered previously (with the exception of the special) and have been blown away with how good they were. My guy had the special which was definitely good, so no complaints there. The onion rings and the fried pickles were greasier than expected. Though I've thought they were delicious in the past, I probably wouldn't order either again. The gyro burger was good, but I could have used a little more sauce. It almost tasted like all of the ingredients didn't entirely fit together. Something was definitely off. It was a friday night and they weren't insanely busy, so I'm not sure I would attribute it to the staff not being on their A game...\n\nDon't get me wrong. Flip is still good. The wait staff is still amazingly good looking. They still make delicious milk shakes. It's just not as amazing as it once was, which really is a little sad.","date":"2010-10-11 18:18:35"} |
| 271 | +``` |
| 272 | + |
| 273 | +{{% alert title="Workshop Question" color="danger" %}} |
| 274 | + |
| 275 | +- What changes are required if you need to make an update to your Dockerfile now? |
| 276 | + |
| 277 | +{{% /alert %}} |
| 278 | + |
| 279 | +## END OF TKO LAB |
| 280 | + |
| 281 | +We hope you found this session and lab useful. We have optional exercise you can do if you finish ahead of schedule, or if you would like to run this at home. Remember this resource can be used at customers to show the value / ease of OTEL. |
| 282 | + |
| 283 | +Please be sure to review our session and provide feedback so we may improve your experience. |
| 284 | + |
| 285 | +Happy Splunking!! |
0 commit comments