{"id":19402838,"url":"https://github.com/cscfi/rahti-course-2019-exercises","last_synced_at":"2025-07-02T03:34:45.460Z","repository":{"id":71819017,"uuid":"221405841","full_name":"CSCfi/rahti-course-2019-exercises","owner":"CSCfi","description":"Exercises for Rahti course held in November 2019","archived":false,"fork":false,"pushed_at":"2019-11-14T14:08:10.000Z","size":254,"stargazers_count":1,"open_issues_count":0,"forks_count":2,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-02-25T00:28:23.003Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/CSCfi.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-11-13T08:10:15.000Z","updated_at":"2020-01-29T15:51:54.000Z","dependencies_parsed_at":"2023-03-11T11:27:32.766Z","dependency_job_id":null,"html_url":"https://github.com/CSCfi/rahti-course-2019-exercises","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/CSCfi/rahti-course-2019-exercises","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CSCfi%2Frahti-course-2019-exercises","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CSCfi%2Frahti-course-2019-exercises/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CSCfi%2Frahti-course-2019-exercises/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CSCfi%2Frahti-course-2019-exercises/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/CSCfi","download_url":"https://codeload.github.com/CSCfi/rahti-course-2019-exercises/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CSCfi%2Frahti-course-2019-exercises/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":263070662,"owners_count":23409161,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-10T11:26:00.753Z","updated_at":"2025-07-02T03:34:45.391Z","avatar_url":"https://github.com/CSCfi.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 1. Authorizing client session and creating a project\n\nCreate a project named `course-training-\u003cnumber\u003e` using the `oc` command\nline interface (CLI) tool.\n\nLocate the project in the web console and verify that it exists using the `oc`\ntool.\n\n# 2. Execute a container in a pod\n\nPre-requisites: *Exercise 1*\n\n## The Docker's hello-world\n\n* Run container image [`hello-world`](https://hub.docker.com/_/hello-world) in\n  a pod called hello-pod.\n* Get the standard output of the container. \n* Verify that the container is crash-looping. Fix it so that it isn't. Replace\n  the container with fixed pod specification.\n\n## Custom \"Hello, world\"\n\n* Run command `echo Hello, world!` inside container from image `alpine:edge`.\n  Name the pod as `custom-hello-pod`.\n\n* Verify that the standard output of the container really is \"Hello, world!\".\n\n## Sleeping pod\n\n* Create a pod based on `alpine:edge` image that sleeps for 7200 seconds and\n  then exits. Name it `sleeping-pod`.\n\n## Cleanup\n\n* Remove the pods named `hello-pod` and `custom-hello-pod`. Let the sleeping pod sleep.\n\n# 3. Navigate Rahti Console\n\nPre-requisites: *Exercise 1, 2*\n\n## Terminal session\n\nOpen terminal session to your sleeping pod using the Rahti GUI console.\n\n* What is the user id? (`id -u`)\n* What is the group id? (`id -g`)\n* Try creating file `/hello` containing string `hello`. Did it work? (`echo hello \u003e /hello`)\n   * Try that with `/tmp/hello`\n* Kill the process that sleeps. Did the pod disappear?\n\n## Cleanup\n\n* Remove the pod `sleeping-pod` using console GUI\n\n# 4. Python application in Rahti\n\nPre-requisites: 1\n\nCreate a Python 3.6 application using the service catalog template named\n\"Python\".\n\nFor sources code of the application, make a fork of the code located at\n`https://github.com/cscfi/rahti-flask-hello` under your own github account.\n\nPlace the application in the project you created in Exercise 1.\n\nName the application `hello-flask-\u003cnumber\u003e`, where `\u003cnumber\u003e` is the number in\nyour training account.\n\nOnce the application is running, find the URL where it is available in the\ninternet.\n\n# 5. Liveness and Readiness probes\n\nPre-requisites: *Exercise 1*\n\nThe following pod waits for 30 seconds, then creates the file `/tmp/alive`\ninside the container, then waits again for 30 seconds and deletes the file.\n\n* Edit the specification so that the container is \"ready\" and \"live\" only if\n  the file `/tmp/alive` exists.\n* Wait for 30 seconds before starting to check if the container is live. \n* Try what happens if the liveness probing starts immediately when the container is started?\n* **Cleanup**: Delete the pod from the cluster afterwards with `oc delete pod probe-tests`.\n\n*Tip #1*: Go to Monitoring page on the Application Console to see the status of\nyour pod.\n\n*Tip #2*: You can monitor the pod with `watch oc describe pod probe-tests` or\n`watch oc get pod probe-tests`\n\n*Tip #3*: The GNU coreutils tool *`cat \u003cfilename\u003e`* returns 0 if the\n\u003cfilename\u003e exists and everything went fine.\n\n```yaml\nkind: Pod\napiVersion: v1\nmetadata:\n  name: probe-tests\nspec:\n  containers:\n  - name: probe-test-container\n    image: centos:7\n    command:\n    - sh\n    - -c\n    - \u003e\n      echo \"Waiting for 30 seconds to go live\" \u0026\u0026 \n      for i in {1..30}; do echo \".\"; sleep 1; done \u0026\u0026 \n      touch /tmp/alive \u0026\u0026 \n      echo \"Now waiting for 30 seconds to go die\" \u0026\u0026 \n      for i in {1..30}; do echo \".\"; sleep 1; done \u0026\u0026 \n      rm /tmp/alive \u0026\u0026 \n      echo \"Going to sleep mode\" \u0026\u0026 \n      sleep inf\n```\n# 6. OOM killer\n\nCreate pod yaml-spec that runs the image\n`docker-registry.default.svc:5000/rahti-course-2019/oom-killer:1`. That image\ncontains a python code, listed in `app/app.py` file, that reserves 10MB more memory\nevery second.\n\nMake sure that the container gets killed when it reserves over 50MB of memory.\n\n# 7. Hello world web server with DeploymentConfig\n\nPre-requisites: *Exercise 1*\n\nIn this exercise, write (or copy-paste from slides) all the API objects in YAML\nplaintext and submit them with `oc create -f ...`. \n\n## DeploymentConfig\n\n* Create a DeploymentConfig that will spawn a pod running image\n  `openshift/hello-openshift`. Name it `hello-openshift` and label it `app:\n  hello-openshift`. Apply the same label `app: hello-openshift` to the pods to\n  be spawned as well.\n  * What is the name of the pod that appeared? *Hint: `oc get pod -l\n    app=hello-openshift`*.\n  * Delete the pod. \n  * What is the name of the pod that appeared?\n* List all objects that have metadata label `app: hello-openshift`. What\n  *Kinds* of objects are listed?\n\n## Service\n\n* Create a Service object that will redirect traffic internally to the pod.\n\n## Route\n\n* Expose the Service to internet at 'hello-rahti-##.rahtiapp.fi', where ## is\n  the number of the training account you are holding.\n  * Secure the route with TLS edge termination policy and redirect\n    insecure traffic to the secure one.\n\n## Cleanup: DeploymentConfig\n\n* If you remove DeploymentConfig, what will happen to the corresponding ReplicationController and Pods?\n* Remove DeploymentConfigs. Did you guess correctly?\n* *Bonus*: Why did it happen?\n\n## Cleanup: The rest\n\n* Remove the Route and the Service objects.\n\n# 8. Application data on persistent volume\n\nPre-requisites: *Exercise 4*\n\nIn the following exercises you are expected to modify the YAML specification\ndirectly with the Rahti Application Console. At the Application Console page,\nthe specification can be found by clicking \"Applications → Deployments\", then\nthe name of the Deployment and finally clicking the upper right corner \"Actions\n→ Edit YAML\".\n\nThis exercise comprises of three parts:\n\n1.  Create and mount a persistent volume with the picture\n    [https://rahti-course-nov-2019.a3s.fi/kitten.jpg](https://rahti-course-nov-2019.a3s.fi/kitten.jpg) \n    to the application `hello-flask-#` made in exercise 4 at\n    `/opt/app-root/src/static`.\n\n    Navigate to `http://hello-flask-#-course-training-#.rahtiapp.fi/kitten` and\n    you should see a kitten.\n\n    *Note*: It doesn't matter in which order you mount and copy, as long as you\n    end up with pods with the file `/opt/app-root/src/static/kitten.jpg`.\n\n    *Tip #1*: Storage can be added and mounted to the DeploymentConfig with the\n    web console.\n\n    *Tip #2*: `oc cp kitten.jpg \u003cpodname\u003e:...` or `oc rsh dc/hello-flask-#` and `curl -L -O \u003curl\u003e`\n\n2.  Create a configmap from file `custom.json` with the following contents:\n    ```json\n    {\n     \"greeting\": \"Custom Hello from custom.json\"\n    }\n\n    *Tip #3*: `oc create configmap ...`\n    ```\n    Place the custom.json file visible in `/opt/app-root/src/config`.\n\n3.  Create a secret and use that secret to bring environment variable\n    \"PASSWORD=secretPassword\" to the application.\n\n    You may change the password above to your liking.\n\n    *Tip #4*: `oc create secret generic ...`\n\nLoading urls http://hello-flask-#-course-training-#.rahtiapp.fi/kitten/ and\nhttp://hello-flask-#-course-training-#.rahtiapp.fi/secret-kitten/secretPassword\n(with # being the training account number entered earlier) should now display\nkittens.\n\n# 9. Webhook to hello-flask \n\nPre-requisites: *Exercise 4*.\n\nYou can now configure GitHub webhook for your hello-flask application, this\nwill trigger your application builds automatically when there are push events\nin your GitHub code.\n\nConfigure a GitHub webhook to the fork repository of rahti-flask-hello you made\nearlier in Exercise 4.\n\n* To find out the secret in the webhook payload look at the BuildConfig\n  of the application: `oc get bc hello-flask-# -o yaml` and look for element\n  `github.secret` in the array `spec.triggers`, where `#` is your training\n  account number. \n* ***Tip #1***: Get the payload URI w/o the secret with `oc describe bc\n  rahti-flask-#`.\n* Edit app.py: Change line 6 to `DefaultTitle=\"Application from Student\n  #\"` where # is your training account number.\n* Commit changes, verify that new build for your application is triggered in\n  Rahti. \n\n# 10. BuildConfigs and Triggers\n\nPre-requisites: *Exercise 1*.\n\n## Inlining Dockerfiles for the base image\n\nCreate a BuildConfig inlining the following `Dockerfile` (don't be tempted to\nuncomment the `#RUN ...` lines yet)\n```Dockerfile\nFROM nginx:mainline-alpine\n\n#RUN chmod g+rwX /var/cache/nginx /var/run /var/log/nginx\n#RUN chgrp -R root /var/cache/nginx\n\nCOPY cfg/default.conf /etc/nginx/conf.d/default.conf\nCOPY cfg/nginx.conf /etc/nginx/nginx.conf\nCOPY cfg/index.html /usr/share/nginx/html/index.html\n#RUN chmod -R g+rX /etc/nginx/\n\nRUN chmod -R g+rX /usr/share/nginx/html\nEXPOSE 8080\n```\n\n* Use the ConfigMap listed in file `nginx-config.yaml` to provide the files\n`cfg/default.conf`, `cfg/nginx.conf` and `cfg/index.html` to the build context.\n  * **Bonus**: Create the nginx-config.yaml file by yourself from files under\n    `cfg/` directory. \n    * ***Tip #1***: `oc create configmap \u003cname\u003e --from-file=\u003cfile1\u003e\n      --from-file=\u003cfile2\u003e ... --dry-run -o yaml`\n* Create an ImageStream object named `my-openshift-nginx` and set the output of\nyour BuildConfig to ImageStreamTag `my-openshift-nginx:latest`.\n\n* ***Tip #2***: Create skeleton code of the objects with `oc new-build my-bc\n--dry-run -o yaml --allow-missing-images -D - \u003e bcs.yaml` and copy-paste the\nDockerfile above and press Control-D.\n\n## Actual website from Github\n\nFork `github.com/cscfi/rahti-httpd-ex` in GitHub. Add the following Dockerfile \nto your fork:\n\n```Dockerfile\nFROM my-openshift-nginx:latest\nCOPY ./ /usr/share/nginx/html/\nRUN rm /usr/share/nginx/html/Dockerfile\nRUN chmod -R g+rX /usr/share/nginx/html\n```\n\nCreate a scaffolding for a new application with the following command\n```bash\n$ oc --name new-app my-static-home https://github.com/\u003cyouraccount\u003e/rahti-httpd-ex \\\n    --dry-run -o yaml \u003e scaffolding.yaml\n```\n\nThe file `scaffolding.yaml` will now contain multiple API objects in a *List*\nobject.\n\nDeploy the objects in `scaffolding.yaml` if it looks okay: `oc create -f scaffolding.yaml`.\n\nThe container `my-static-home` should be in a crash-loop right now. The lines\nstarting with `#RUN ...` in the first Dockerfile should not have be commented\nout in the first place after all―the correct Dockerfile looks like be:\n\n```Dockerfile\nFROM nginx:mainline-alpine\n\nRUN chmod g+rwX /var/cache/nginx /var/run /var/log/nginx\nRUN chgrp -R root /var/cache/nginx\n\nCOPY cfg/default.conf /etc/nginx/conf.d/default.conf\nCOPY cfg/nginx.conf /etc/nginx/nginx.conf\nCOPY cfg/index.html /usr/share/nginx/html/index.html\nRUN chmod -R g+rX /etc/nginx/\n\nRUN chmod -R g+rX /usr/share/nginx/html\nEXPOSE 8080\n```\n\nModify the BuildConfig housing Dockerfile defined in the first part in and\nrebuild the image in ImageStreamTag `my-openshift-nginx:latest`. ***Tip #3***:\nYou can modify the Dockerfile directly from the web console: Locate the\nBuildConfig and click Actions → Edit.\n\nOnce build has been completed, the final application should work and you can\nmake a Route to it.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcscfi%2Frahti-course-2019-exercises","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcscfi%2Frahti-course-2019-exercises","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcscfi%2Frahti-course-2019-exercises/lists"}