forked from hswaw/hscloud
/doc/codelabs: add tutorials
parent
a6592b845c
commit
6a33e8f442
|
@ -0,0 +1,117 @@
|
||||||
|
# Building your own Flask web service
|
||||||
|
|
||||||
|
In this chapter, we will build our own web service using the Flask framework, dockerize it and register it in the registry.
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
You will require `docker` in this example. Install it from your standard shell.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -fsSL https://get.docker.com -o get-docker.sh
|
||||||
|
sudo sh get-docker.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
You can actually create, build and register docker image in completely other environment, and just deploy it to kubernetes in hscloud environment.
|
||||||
|
|
||||||
|
It is advised to have done [Run first service](run-first-service.md) chapter.
|
||||||
|
|
||||||
|
## Steps
|
||||||
|
|
||||||
|
We create a simple Flask application:
|
||||||
|
|
||||||
|
```py
|
||||||
|
# app.py
|
||||||
|
|
||||||
|
from flask import Flask
|
||||||
|
|
||||||
|
app = Flask(__name__)
|
||||||
|
|
||||||
|
@app.route('/')
|
||||||
|
|
||||||
|
def hello_world():
|
||||||
|
return 'Hello, World!'
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
app.run()
|
||||||
|
```
|
||||||
|
|
||||||
|
We can check if the application works by running it:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip3 install flask
|
||||||
|
python3 app.py
|
||||||
|
```
|
||||||
|
|
||||||
|
Now we create `Dockerfile` file for our application:
|
||||||
|
|
||||||
|
```Dockerfile
|
||||||
|
# Use an official Python runtime as a base image
|
||||||
|
FROM python:3.8-slim-buster
|
||||||
|
|
||||||
|
# Set the working directory in docker
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Copy the current directory contents into the container at /app
|
||||||
|
COPY . /app
|
||||||
|
|
||||||
|
# Install any needed packages specified in requirements.txt
|
||||||
|
RUN pip install --upgrade pip && \
|
||||||
|
pip install flask gunicorn
|
||||||
|
|
||||||
|
# Set environment variables
|
||||||
|
ENV FLASK_APP=app.py
|
||||||
|
ENV FLASK_RUN_HOST=0.0.0.0
|
||||||
|
|
||||||
|
# Expose port 5000 for the Flask app to listen on
|
||||||
|
EXPOSE 5000
|
||||||
|
|
||||||
|
# Define command to run the application using gunicorn
|
||||||
|
CMD ["gunicorn", "-w", "4", "-b", ":5000", "app:app"]
|
||||||
|
```
|
||||||
|
|
||||||
|
We can test if the application works in Docker:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker build -t myflask . # Build the image
|
||||||
|
docker run -d -p 5000:5000 myflask # Run the container
|
||||||
|
```
|
||||||
|
|
||||||
|
We can check if the application works by opening the browser at `http://localhost:5000`.
|
||||||
|
|
||||||
|
## Pushing the image to the registry
|
||||||
|
|
||||||
|
First, we need to authenticate to the registry:
|
||||||
|
|
||||||
|
```
|
||||||
|
https://registry.k0.hswaw.net
|
||||||
|
```
|
||||||
|
|
||||||
|
You should get command similar to:
|
||||||
|
|
||||||
|
```
|
||||||
|
docker login -u $hs_username -p *************** https://registry.k0.hswaw.net
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
Now we need to create local server for our docker image:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker tag myflask registry.k0.hswaw.net/$hs_username/myflask:latest
|
||||||
|
docker push registry.k0.hswaw.net/$hs_username/myflask:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
To check if the image is in the registry, you can use:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X GET https://registry.k0.hswaw.net/v2/$hs_username/myflask/tags/list
|
||||||
|
```
|
||||||
|
|
||||||
|
To remove the image from the registry, you can use:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker rmi registry.k0.hswaw.net/$hs_username/myflask:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
## Next step
|
||||||
|
|
||||||
|
[Deploying web app](deploying-web-app.md)
|
|
@ -0,0 +1,95 @@
|
||||||
|
# Deploying docker image on hscloud
|
||||||
|
|
||||||
|
In this chapter, we will deploy our registered docker image on `hscloud` as a simple HTTP kube service with HTTPS from Let's Encrypt.
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
Registered image from [Building web app](building-web-app.md):
|
||||||
|
|
||||||
|
```
|
||||||
|
https://registry.k0.hswaw.net/$hs_username/myflask:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
## Steps
|
||||||
|
|
||||||
|
We create a `prod.jsonnet` file in location `//personal/$hs_username/myflask/prod.jsonnet`:
|
||||||
|
|
||||||
|
|
||||||
|
```jsonnet
|
||||||
|
# Remember to replace $hs_username with your SSO username!
|
||||||
|
|
||||||
|
local kube = import "../../../kube/kube.libsonnet";
|
||||||
|
|
||||||
|
{
|
||||||
|
local top = self,
|
||||||
|
local cfg = self.cfg,
|
||||||
|
|
||||||
|
cfg:: {
|
||||||
|
name: 'web-app',
|
||||||
|
namespace: 'personal-$hs_username',
|
||||||
|
domain: 'web-app.$hs_username.hscloud.ovh',
|
||||||
|
image: 'registry.k0.hswaw.net/$hs_username/myflask:latest',
|
||||||
|
},
|
||||||
|
|
||||||
|
ns: kube.Namespace(cfg.namespace),
|
||||||
|
|
||||||
|
deployment: top.ns.Contain(kube.Deployment(cfg.name)) {
|
||||||
|
spec+: {
|
||||||
|
replicas: 1,
|
||||||
|
template+: {
|
||||||
|
spec+: {
|
||||||
|
containers_: {
|
||||||
|
default: kube.Container("default") {
|
||||||
|
image: cfg.image,
|
||||||
|
ports_: {
|
||||||
|
http: { containerPort: 5000 },
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
service: top.ns.Contain(kube.Service(cfg.name)) {
|
||||||
|
target_pod:: top.deployment.spec.template,
|
||||||
|
},
|
||||||
|
|
||||||
|
ingress: top.ns.Contain(kube.Ingress(cfg.name)) {
|
||||||
|
metadata+: {
|
||||||
|
annotations+: {
|
||||||
|
"kubernetes.io/tls-acme": "true",
|
||||||
|
"cert-manager.io/cluster-issuer": "letsencrypt-prod",
|
||||||
|
"nginx.ingress.kubernetes.io/proxy-body-size": "0",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
spec+: {
|
||||||
|
tls: [ { hosts: [ cfg.domain ], secretName: cfg.name + "-tls" } ],
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
host: cfg.domain,
|
||||||
|
http: {
|
||||||
|
paths: [
|
||||||
|
{ path: "/", backend: top.service.name_port },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
We can now deploy our application:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubecfg update prod.jsonnet
|
||||||
|
```
|
||||||
|
|
||||||
|
The application should be available at `http://web-app.$hs_username.hscloud.ovh`. You will have to wait several seconds for the working HTTPS service.
|
||||||
|
|
||||||
|
To remove the application, execute:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubecfg delete prod.jsonnet
|
||||||
|
```
|
|
@ -0,0 +1,84 @@
|
||||||
|
# Building an environment
|
||||||
|
|
||||||
|
In this chapter, I will describe how to build an environment in which we will build hscloud services.
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
You need `git` and `curl`. On Ubuntu you can install them with:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo apt install git curl
|
||||||
|
```
|
||||||
|
|
||||||
|
Clone the repository with the source code of the cloud services:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone "https://gerrit.hackerspace.pl/hscloud"
|
||||||
|
cd hscloud
|
||||||
|
```
|
||||||
|
|
||||||
|
If you want to commit anything on gerrit, we have to do additional steps ([source](https://gerrit.hackerspace.pl/admin/repos/hscloud,general)):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mkdir -p .git/hooks/
|
||||||
|
curl -Lo .git/hooks/commit-msg https://gerrit.hackerspace.pl/tools/hooks/commit-msg
|
||||||
|
chmod +x .git/hooks/commit-msg
|
||||||
|
```
|
||||||
|
|
||||||
|
## Steps
|
||||||
|
|
||||||
|
We can configure the environment using niix-shell. To do this, we install `nix`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sh <(curl -L https://nixos.org/nix/install) --daemon
|
||||||
|
```
|
||||||
|
|
||||||
|
And we start it (from inside the `hscloud` folder):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
nix-shell
|
||||||
|
```
|
||||||
|
|
||||||
|
We now use the `bazel` tool to build and run the necessary services, including `prodaccess` and `kubectl`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bazel build //tools:install
|
||||||
|
bazel run //tools:install
|
||||||
|
```
|
||||||
|
|
||||||
|
Now we can request to grant us access to the hscloud cluster through the [prodaccess](https://pkg.go.dev/code.hackerspace.pl/hscloud/cluster/prodaccess#section-readme) tool. In place of `$hs_username` insert the username in SSO hackerspace:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
hs_username=$USER # if your username is the same as your SSO username
|
||||||
|
prodaccess -username $hs_username
|
||||||
|
```
|
||||||
|
|
||||||
|
If you do not have access to the cluster, contact [@q3k](q3k:hackerspace.pl) or [@inf](informatic:hackerspace.pl) within [Matrix](https://matrix.hackerspace.pl/).
|
||||||
|
|
||||||
|
To check if we have access to the cluster, we can run the command:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# shows the Kubernetes version
|
||||||
|
kubectl version
|
||||||
|
|
||||||
|
# shows the statistics of the cluster
|
||||||
|
kubectl top nodes
|
||||||
|
```
|
||||||
|
|
||||||
|
We can also call the public Docker image (again, in place of `$hs_username`, insert the username in SSO hackerspace):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# to create an instance of (sub) alpine
|
||||||
|
kubectl -n personal-$hs_username run --image=alpine:latest -it foo
|
||||||
|
```
|
||||||
|
|
||||||
|
If you want to delete the instance, run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# to delete an instance (sub) of alpine
|
||||||
|
kubectl -n personal-$hs_username delete pod foo
|
||||||
|
```
|
||||||
|
|
||||||
|
## Next step
|
||||||
|
|
||||||
|
Next step: [Run first service](run-first-service.md)
|
|
@ -0,0 +1,103 @@
|
||||||
|
# Running a public service in hscloud
|
||||||
|
|
||||||
|
In this chapter, I will show you how to run an existing service that will be publicly available on the Internet.
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
Done steps from [**Prepare environment**](prepare-environment.md) chapter.
|
||||||
|
|
||||||
|
## Creating a copy of ldapweb
|
||||||
|
|
||||||
|
We start in the `hscloud` folder, with the `nix-shell` environment enabled. If you don't have your namespace in the `//personal` folder yet, we create it:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mkdir personal/$hs_username
|
||||||
|
```
|
||||||
|
|
||||||
|
We copy the configuration of the `ldapweb` service into the workspace:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp -r hswaw/ldapweb/ personal/$hs_username/
|
||||||
|
cd personal/$hs_username/ldapweb/
|
||||||
|
```
|
||||||
|
|
||||||
|
## Modifying the service
|
||||||
|
|
||||||
|
The configuration of `ldapweb` is contained in the `prod.jsonnet` file. The format of `jsonnet` is very similar to `json`, but allows the use of variables, functions, and the import of other files.
|
||||||
|
|
||||||
|
We are interested in the initial part of the file:
|
||||||
|
|
||||||
|
```jsonnet
|
||||||
|
local kube = import "../../kube/kube.libsonnet"
|
||||||
|
|
||||||
|
{
|
||||||
|
local top = self,
|
||||||
|
local cfg = self.cfg,
|
||||||
|
|
||||||
|
cfg:: {
|
||||||
|
name: 'ldapweb',
|
||||||
|
namespace: 'ldapweb',
|
||||||
|
domain: 'profile.hackerspace.pl',
|
||||||
|
image: 'registry.k0.hswaw.net/radex/ldap-web:1695486391',
|
||||||
|
},
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The import is done from the `kube.libsonnet` file in the `kube` folder in the `hscloud` folder. In order for the import to proceed correctly in this case, we need to go back one more folder: `../../../kube/kube.libsonnet`.
|
||||||
|
|
||||||
|
The `hscloud` configuration only allows the namespace in `personal-$hs_username` format. In addition, we need to change the domain to `*.$hs_username.hscloud.ovh`. Finally, we change the service name to `test`.
|
||||||
|
|
||||||
|
Finally, the above fragment of the `prod.jsonnet` file should look like this:
|
||||||
|
|
||||||
|
|
||||||
|
```jsonnet
|
||||||
|
# remember to replace $hs_username with your username!
|
||||||
|
|
||||||
|
local kube = import "../../../kube/kube.libsonnet";
|
||||||
|
|
||||||
|
{
|
||||||
|
local top = self,
|
||||||
|
local cfg = self.cfg,
|
||||||
|
|
||||||
|
|
||||||
|
cfg:: {
|
||||||
|
name: 'test',
|
||||||
|
namespace: 'personal-$hs_username',
|
||||||
|
domain: 'test.$hs_username.hscloud.ovh',
|
||||||
|
image: 'registry.k0.hswaw.net/radex/ldap-web:1695486391',
|
||||||
|
},
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
We log into the cluster:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
hs_username=$USER # if your username is the same as your SSO username
|
||||||
|
prodaccess -username $hs_username
|
||||||
|
```
|
||||||
|
|
||||||
|
We invoke the command to apply the changes:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubecfg update prod.jsonnet
|
||||||
|
```
|
||||||
|
|
||||||
|
Our service should be at `https://test.$hs_username.hscloud.ovh/`. During the first couple of minutes we will get a message about an invalid certificate, because the Let's Encrypt service has not yet managed to generate a certificate for our domain.
|
||||||
|
|
||||||
|
To remove the service, call:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubecfg delete prod.jsonnet
|
||||||
|
```
|
||||||
|
|
||||||
|
or
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubectl delete service test -n personal-$hs_username
|
||||||
|
```
|
||||||
|
|
||||||
|
## Next step
|
||||||
|
|
||||||
|
[Building web app](building-web-app.md)
|
|
@ -189,5 +189,5 @@ Further steps
|
||||||
|
|
||||||
- If you need a **Git refresher** - we highly recommend the [Git Visual Reference](https://marklodato.github.io/visual-git-guide/index-en.html)
|
- If you need a **Git refresher** - we highly recommend the [Git Visual Reference](https://marklodato.github.io/visual-git-guide/index-en.html)
|
||||||
- [Bazel & Go basics](bazel-go.md) will (TODO) guide you through building some code using Bazel, and then writing a tiny bit of Go code of your own.
|
- [Bazel & Go basics](bazel-go.md) will (TODO) guide you through building some code using Bazel, and then writing a tiny bit of Go code of your own.
|
||||||
- **TODO** will guide you through accessing our production Kubernetes cluster and running some code on it.
|
- [Prepare environment with nix](prepare-environment.md) will guide you through accessing our production Kubernetes cluster and running some code on it.
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,10 @@ Getting started
|
||||||
- [**Checking out hscloud**](getting-started/checking-out.md) - how to get a copy of hscloud, how to navigate around it, and what's what. This is nearly **mandatory** for anyone who wishes to interact with hscloud.
|
- [**Checking out hscloud**](getting-started/checking-out.md) - how to get a copy of hscloud, how to navigate around it, and what's what. This is nearly **mandatory** for anyone who wishes to interact with hscloud.
|
||||||
- [**Your First Change**](getting-started/your-first-change.md) - how to use Gerrit and git to send your first change to hscloud, and an intro to personal directories. Using Gerrit can be somewhat confusing even (or especially) if you're used to Gitflow or GitHub.
|
- [**Your First Change**](getting-started/your-first-change.md) - how to use Gerrit and git to send your first change to hscloud, and an intro to personal directories. Using Gerrit can be somewhat confusing even (or especially) if you're used to Gitflow or GitHub.
|
||||||
- [**Bazel & Go basics**](getting-started/bazel-go.md) - will (TODO) guide you through building some code using Bazel, and then writing a tiny bit of Go code of your own.
|
- [**Bazel & Go basics**](getting-started/bazel-go.md) - will (TODO) guide you through building some code using Bazel, and then writing a tiny bit of Go code of your own.
|
||||||
|
- [**Preparing kubernetes environment**](getting-started/prepare-environment.md) - how to build environment using `nix` and `bazel`, to be able to run first kubernetes pod.
|
||||||
|
- [**Creating test pod**](getting-started/run-first-service.md) - how to deploy first service from available image.
|
||||||
|
- [**Building web app**](getting-started/building-web-app.md) - how to prepare our first Flask app and register it on hscloud k8s registry.
|
||||||
|
- [**Deploying web app**](getting-started/deploying-web-app.md) - how to deploy our registed web app.
|
||||||
|
|
||||||
See also
|
See also
|
||||||
--------
|
--------
|
||||||
|
|
Loading…
Reference in New Issue