Demo Setup

Visual Studio Code Remote Development (Containers)

To limit the amount of incompatibility in setting up the demo and tutorial, all the commands that are listed are expected to be run in an appropriately setup container. Specifically, this demo supports the VS Code Remote Development (Containers) as can be seen in the .devcontainer directory.

All commands that are listed for the demo and tutorial are assumed to be run from within the terminal (and thus "devcontainer") of VSCode. The container has been setup to have all the necessary command and tools necessary to run and compile the tutorial/demo.

This tutorial/demo was developed using Visual Studio Code Remote Development on a MacBook Pro using Docker for Desktop (Mac)

Connecting to Minikube cluster

If you have made a minikube instance available externally, then you can setup your environment to work with that cluster. There are some pre-requisites though

  1. You must have ssh access to the machine running minikube (call it MINIKUBE_HOST)

  2. The MINIKUBE_HOST needs to have scp installed

  3. You need to have a key pair generated (e.g. from ssh-keygen) and have access to both the public and private key

    • Public key path is PUBLIC_KEY_PATH

    • Private key path is PRIVATE_KEY_PATH

  4. You must be able to ssh login as the user who created the minikube cluster on the remote machine (call it MINIKUBE_USER)

Once you have satisfied the pre-requisites, here’s how you can get access to the cluster

  1. Copy the public key to the remote machine to allow access using the private key:

    ssh-copy-id -i ${PUBLIC_KEY_PATH} ${MINIKUBE_USER}@${MINIKUBE_HOST}
  2. Next, run the following command to pull necessary certs and create a suitable kubeconfig

    ${DEMO_HOME}/scripts/create-kubeconfig.sh ${MINIKUBE_HOST} ${PRIVATE_KEY_PATH} ${MINIKUBE_USER}

Building

To build a new containerized demo app, follow these steps:

  1. Rebuild parent project

    mvn package -f ${DEMO_HOME}/demo

    You need to build the parent project because the demo-app and demo-operator rely on a common log-module package that is not uploaded to maven. Thus all three are bundled together so that the parent project can handle the dependencies. This is why you will see this warning when compiling:

    [WARNING]
    [WARNING] Some problems were encountered while building the effective model for org.mhildenb.operatortutorial:demo-app:jar:1.0.0
    [WARNING] 'dependencies.dependency.systemPath' for org.mhildenb.operatortutorial:log-module:jar should not point at files within the project directory, ${project.basedir}/../log-module/target/log-module-1.0.0.jar will be unresolvable by dependent projects @ line 44, column 19
    [WARNING]
    [WARNING] It is highly recommended to fix these problems because they threaten the stability of your build.
    [WARNING]
    [WARNING] For this reason, future Maven versions might no longer support building such malformed projects.
    [WARNING]
  2. This should show all test cases passing and in the output you should see something like this near the end of the output:

    [INFO] [io.quarkus.deployment.QuarkusAugmentor] Quarkus augmentation completed in 6138ms
    [INFO] ------------------------------------------------------------------------
    [INFO] Reactor Summary:
    [INFO]
    [INFO] demo 1.0 ........................................... SUCCESS [  0.009 s]
    [INFO] log-module 1.0.0 ................................... SUCCESS [  8.061 s]
    [INFO] demo-app 1.0.0 ..................................... SUCCESS [ 13.832 s]
    [INFO] demo-operator 1.0.0 ................................ SUCCESS [ 10.445 s]
    [INFO] ------------------------------------------------------------------------
    [INFO] BUILD SUCCESS
    [INFO] ------------------------------------------------------------------------
    [INFO] Total time:  34.749 s
    [INFO] Finished at: 2021-02-08T07:46:59Z
    [INFO] ------------------------------------------------------------------------

Deploying demo-app

  1. Next, specifically build the demo-app for container image:

    You first must set the following environment variables to log into your chosen image registry (e.g. quay.io):

    • USER

    • PASSWORD

    mvn -B package -DskipTests \
            -Dquarkus.container-image.build=true \
            -Dquarkus.container-image.push=true \
            -Dquarkus.container-image.registry=quay.io \
            -Dquarkus.container-image.group=mhildenb \
            -Dquarkus.container-image.name=tutorial-operator-demoapp \
            -Dquarkus.jib.base-jvm-image=fabric8/java-alpine-openjdk11-jre \
            -Dquarkus.container-image.username=${USER} -Dquarkus.container-image.password=${PASSWORD} \
            -Dquarkus.container-image.tag=latest \
            -f ${DEMO_HOME}/demo/demo-app
  2. Once the new image is built, you can deploy the demo-app, with the following command:

    kubectl apply -f ${DEMO_HOME}/demo/kube/demo-app/demo-app-deploy.yaml

    This will deploy to the current context namespace. Use -n parameter to deploy to another namespace

Deploying Demo Operator

  1. Next, specifically build the demo-operator for container image:

    You first must set the following environment variables to log into your chosen image registry (e.g. quay.io):

    • USER

    • PASSWORD

    mvn -B package -DskipTests \
            -Dquarkus.container-image.build=true \
            -Dquarkus.container-image.push=true \
            -Dquarkus.container-image.registry=quay.io \
            -Dquarkus.container-image.group=mhildenb \
            -Dquarkus.container-image.name=tutorial-operator-demoop \
            -Dquarkus.jib.base-jvm-image=fabric8/java-alpine-openjdk11-jre \
            -Dquarkus.container-image.username=${USER} \
            -Dquarkus.container-image.password=${PASSWORD} \
            -Dquarkus.container-image.tag=latest \
            -f ${DEMO_HOME}/demo/demo-operator
  2. Once the new image is built, you can deploy the demo-operator, with the following command:

    kubectl apply -f ${DEMO_HOME}/demo/kube/operator-deploy.yaml

    This currently MUST deploy to the operator-test namespace. Make sure this namespace is targeted when deploying the operator.

Running integration tests

log-module

The logging module has some tests that exercise the LoggerClient (which sets and gets the Logger.LogLevel at runtime from the demo-app). To run these tests:

  1. First, connect to a running demo app. If using minikube, easiest might be to port-forward to the app you just deployed

    oc port-forward svc/demo-app 8084:8080
  2. You can override the host that will be used for the integration test by either changing it (log-module.test.integration-uri) in the application.properties file or you can set in the environment like this:

    export log_module_test_integration_uri="http://localhost:8084"
  3. Finally, build the (log-module) project (or parent) with the integrationTest system property

    mvn clean package -DintegrationTest -f $DEMO_HOME/demo/log-module

Exposing Services in Minikube

Fedora

  1. Expose the deployment as a NodePort

    kubectl expose deploy/demo-app --type NodePort
  2. Next create a proxy in minikube

    minikube service --url demo-app -n operator-test
  3. Gather the IP Address and Port and set in variables TARGET_IP and TARGET_PORT respectively

    minikube service list
    |---------------|------------|--------------|---------------------------|
    |   NAMESPACE   |    NAME    | TARGET PORT  |            URL            |
    |---------------|------------|--------------|---------------------------|
    | default       | kubernetes | No node port |
    | kube-system   | kube-dns   | No node port |
    | operator-test | demo-app   |         #8080#| #http://192.168.49.2:30453# |
    |---------------|------------|--------------|---------------------------|
  4. Update the iptables with the following:

    iptables -t nat -A PREROUTING -p tcp --dport 8008 -j DNAT --to-destination $TARGET_IP:$TARGET_PORT

WSL

  1. Open a new fedora wsl instance

  2. run the following:

    minikube service --url demo-app -n operator-test
  3. You should get output like the following:

    😿  service operator-test/demo-app has no node port
    🏃  Starting tunnel for service demo-app.
    |---------------|----------|-------------|------------------------|
    |   NAMESPACE   |   NAME   | TARGET PORT |          URL           |
    |---------------|----------|-------------|------------------------|
    | operator-test | demo-app |             | http://127.0.0.1:40289 |
    |---------------|----------|-------------|------------------------|
    http://127.0.0.1:40289
  4. Open a powershell on the host as Administrator

  5. Set the port of the above command a variable $svcPort

  6. In powershell on the host, run the following command

     netsh interface portproxy add v4tov4 listenaddress=0.0.0.0 listenport=8086 connectaddress=127.0.0.1 connectport=$svcPort
  7. You can then access the service by calling the window host’s IP address at port 8086

Useful commands

To override the URL that should be used when accessing a pod (useful when running operator locally) set the property demo-operator.pod-uri-override in the application properties of the demo-operator. Alternatively, set this in the environment before running mvn:quarkus:dev

DEMO_OPERATOR_POD_URI_OVERRIDE="http://192.168.86.48:8086"

To change the number of replicas to 0

kubectl patch deploy/demo-app --type='json' -p='[{"op": "replace", "path": "/spec/replicas", "value": 0 }]'

To delete the appops custome resouce with the finalizer:

kubectl patch appops/my-bespoke-app --type='json' -p='[{"op": "remove", "path": "/metadata/finalizers" }]'

To watch the cr without managed fields:

kubectl patch appops/my-bespoke-app -o yaml --type='json' -p='[{"op": "remove", "path": "/metadata/managedFields" }]' --dry-run

# watch updates every second with this command
watch -d -n 1 -x -- kubectl patch appops/my-bespoke-app -o yaml --type='json' -p='[{"op": "remove", "path": "/metadata/managedFields" }, {"op": "remove", "path": "/metadata/annotations" } ]' --dry-run=client