c2sr bootcamp docs Help

Inverter Deployment Task

This is the fourth and most critical component in our data pipeline. In this tutorial, you will deploy the inverter, a custom application that simulates a SunSpec-compliant solar inverter. It acts as the final destination for our data, consuming messages from the Kafka topic you set up earlier and exposing the data via the Modbus protocol on port 502.

This task is designed to teach you how to deploy a Kubernetes application that consumes data from a message queue and exposes a non-HTTP protocol (Modbus/TCP) to the outside world using a NodePort service.

In this tutorial, you will be tasked to:

  • Deploy a consumer application that connects to Kafka.

  • Configure the application to run on a specific worker node (nano).

  • Use advanced environment variable injection to get the host node's IP address.

  • Create a NodePort service with a specific externalTrafficPolicy to correctly route external traffic.

  • Verify that the inverter is running and consuming data from the Kafka topic.

Before you start

Make sure that:

  • The Zookeeper, Kafka, and Streamer deployments are all running successfully.

  • The ghcr-pull-secret exists in the cluster for pulling private images.

  • You are SSHed into the k3smain node and have switched to the shared user account.

Part 1: Create the Inverter Deployment Manifest

Your first goal is to create a Kubernetes deployment file named inverter-deployment.yaml.

Deployment Requirements

The Inverter instance must be configured with the following specifications:

  1. Deployment Name: The deployment must be named inverter.

  2. Node Affinity: This is important. The pod must be scheduled to run on the node named nano, not k3smain.

  3. Container Image: Use the ghcr.io/decsresearch/c2sr-bootcamp-inverter:latest image.

  4. Image Pull Secret: Reference the ghcr-pull-secret to authorize pulling the image.

  5. Port: The container must expose the Modbus port, 502.

  6. Environment Configuration:

    • KAFKA_HOST: The name of the Kafka service (kafka-service).

    • KAFKA_INPUT_TOPIC: The topic to consume from. This must match the topic the streamer is producing to (nano).

    • NODE_NAME: A logical name for the inverter, set to nano.

    • NODE_IP: This must be set dynamically to the IP of the host node the pod is running on. This is achieved using valueFrom and a fieldRef.

    • INVERTER_HOST_IP: The IP address the inverter service should listen on inside the container (0.0.0.0).

    • INVERTER_PORT: The port the inverter service should listen on inside the container (502).

Skeleton File for Deployment

Create a file named inverter-deployment.yaml and fill it out according to the requirements above.

# inverter-deployment.yaml --- apiVersion: apps/v1 kind: Deployment metadata: # Requirement 1: Specify the deployment name name: <Your-Deployment-Name> spec: selector: matchLabels: app: inverter template: metadata: labels: app: inverter spec: containers: - name: inverter # Requirement 3: Specify the container image image: <Your-Image-Path> imagePullPolicy: Always ports: # Requirement 5: Expose the container port - containerPort: <Your-Port> # Requirement 6: Add all 6 required environment variables env: - name: KAFKA_HOST value: <Value> - name: KAFKA_INPUT_TOPIC value: <Value> - name: NODE_NAME value: <Value> - name: NODE_IP # For this one, you need to use valueFrom valueFrom: fieldRef: fieldPath: <Path-To-Host-IP> # ... add remaining env vars ... # Requirement 4: Add the image pull secret imagePullSecrets: - name: <Your-Secret-Name> # Requirement 2: Add the correct node selector for the 'nano' node nodeSelector: kubernetes.io/hostname: <Your-Node-Name>

Part 2: Expose the Inverter with a Service

To allow the SunSpec client (which runs outside the cluster) to connect to the inverter's Modbus port, you must create a NodePort service.

Service Requirements

The Service must:

  1. Have the name inverter-service.

  2. Be of type NodePort.

  3. Set the externalTrafficPolicy to Local. This ensures traffic is only sent to the pod on the node that receives the request, which is necessary for this setup.

  4. Expose the TCP protocol on port 502, mapped to targetPort 502 and a static nodePort of 30502.

  5. Use a selector to correctly identify the inverter pod (app: inverter).

Skeleton File for Service

Create a second file named inverter-service.yaml and complete the skeleton below.

# inverter-service.yaml --- apiVersion: v1 kind: Service metadata: # Requirement 1: Specify the service name name: <Your-Service-Name> spec: # Requirement 2: Set the service type type: <Your-Service-Type> selector: # Requirement 5: Add the correct selector app: <Your-App-Label> ports: # Requirement 4: Define protocol, port, targetPort, and nodePort - protocol: <Protocol> port: <Service-Port> targetPort: <Pod-Port> nodePort: <Your-Node-Port> # Requirement 3: Set the external traffic policy externalTrafficPolicy: <Policy-Value>

Part 3: Deployment and Verification

Once you have created both YAML files, apply them and check the logs. The logs will confirm that the inverter has connected to Kafka and is processing messages from the streamer.

  1. Apply the manifests: kubectl apply -f inverter-deployment.yaml kubectl apply -f inverter-service.yaml

  2. Verify the deployment: kubectl get pods -l app=inverter -o wide (Use -o wide to confirm it is running on the nano node).

  3. Check for data consumption: kubectl logs -f <pod name>

If the logs show the inverter is successfully consuming messages, you are ready for the final step: connecting with the SunSpec client.

Solutions

# inverter-deployment.yaml --- apiVersion: apps/v1 kind: Deployment metadata: name: inverter spec: selector: matchLabels: app: inverter template: metadata: labels: app: inverter spec: containers: - name: inverter image: ghcr.io/decsresearch/c2sr-bootcamp-inverter:latest imagePullPolicy: Always ports: - containerPort: 502 env: - name: KAFKA_HOST value: "kafka-service" - name: KAFKA_INPUT_TOPIC value: "input_topic" - name: NODE_NAME value: nano - name: NODE_IP valueFrom: fieldRef: fieldPath: status.hostIP - name: INVERTER_HOST_IP value: 0.0.0.0 - name: INVERTER_PORT value: "502" imagePullSecrets: - name: ghcr-pull-secret nodeSelector: kubernetes.io/hostname: nano
# inverter-service.yaml --- apiVersion: v1 kind: Service metadata: name: inverter-service spec: type: NodePort selector: app: inverter ports: - protocol: TCP port: 502 targetPort: 502 nodePort: 30502 externalTrafficPolicy: Local
Last modified: 22 June 2025