In this tutorial, we will build a simple web app component written in Python that you can use for testing. It reads in an env variable TARGET and prints “Hello ${TARGET}!“. If TARGET is not specified, it will use “World” as the TARGET.
- A Kubernetes cluster with Rudr installed. Follow the installation instructions if you need to create one.
- Docker installed and running on your local machine, and a Docker Hub account configured (we’ll use it for a container registry).
The following instructions will lead you to build an image from source, you can get all the files mentioned here in the app folder.
- Create a new directory and cd into it:
mkdir app cd app
- Create a file named
app.py
and copy the code fromapp/app.py
- Create a file named
Dockerfile
and copy the code fromapp/Dockerfile
, See official Python docker image for more details. - Use Docker to build the sample code into a container. To build and push with Docker Hub, run these commands replacing
oamdev
with your Docker Hub username:# Build the container on your local machine docker build -t oamdev/helloworld-python:v1 . # Push the container to docker registry docker push oamdev/helloworld-python:v1
Now we have a docker image named oamdev/helloworld-python:v1
, so we can use this image to create a component schematics file.
- Choose the workloadType: the
helloworld-python
is very typical web application, it is stateless, always running as a service, can be replicated. So we usecore.oam.dev/v1alpha1.Server
without doubt. - Fill the container spec and make ENV configurable: obviously we have two major environment variables in the image, one is TARGET and the other is PORT.
- Make parameters so we could let Application Configuration configure these environments.
After these three concerns, we could figure out this basic component schematic yaml like below:
apiVersion: core.oam.dev/v1alpha1
kind: ComponentSchematic
metadata:
name: helloworld-python-v1
spec:
name: helloworld-python
workloadType: core.oam.dev/v1alpha1.Server
containers:
- name: foo
image: oamdev/helloworld-python:v1
env:
- name: TARGET
fromParam: target
- name: PORT
fromParam: port
ports:
- type: tcp
containerPort: 9999
name: http
parameters:
- name: target
type: string
default: World
- name: port
type: string
default: '9999'
Let's name it helloworld-python-component.yaml
and put it into the examples
folder.
Finally we could apply this yaml to the platform and let our operators to deploy it.
$ kubectl apply -f examples/helloworld-python-component.yaml
componentschematic.core.oam.dev/helloworld-python-v1 created
You can check if your component schematic is OK with:
$ kubectl get comp
NAME AGE
helloworld-python-v1 15s
Yeah, we have successfully built a component from source now.
We assume a component is immutable. If we want to upgrade a component, the easiest way is to modify the component and change the name suffix with a new version.
For example, we change the code from Hello
to Goodbye
.
import os
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
target = os.environ.get('TARGET', 'World')
- return 'Hello {}!\n'.format(target)
+ return 'Goodbye {}!\n'.format(target)
if __name__ == "__main__":
app.run(debug=True, host='0.0.0.0', port=int(os.environ.get('PORT', "8080")))
Build and create image with a new tag.
docker build -t oamdev/helloworld-python:v2 .
docker push oamdev/helloworld-python:v2
Change the component with a new name.
apiVersion: core.oam.dev/v1alpha1
kind: ComponentSchematic
metadata:
- name: helloworld-python-v1
- name: helloworld-python-v2
spec:
name: helloworld-python
workloadType: core.oam.dev/v1alpha1.Server
containers:
- name: foo
- image: oamdev/helloworld-python:v1
+ image: oamdev/helloworld-python:v2
env:
- name: TARGET
fromParam: target
- name: PORT
fromParam: port
ports:
- type: tcp
containerPort: 9999
name: http
parameters:
- name: target
type: string
default: World
- name: port
type: string
default: '9999'
Apply the changed component:
$ kubectl apply -f examples/helloworld-python-component.yaml
componentschematic.core.oam.dev/helloworld-python-v2 created
Now we have two components:
$ kubectl get comp
NAME AGE
helloworld-python-v1 1h
helloworld-python-v2 27s
They could be used by operator in application configuration.