Guided Exercise: Expose a Virtual Machine Over the Network
We will work with the cirros testvm again:
kubectl apply -f https://kubevirt.io/labs/manifests/vm.yaml
Remember to start the vm after creation:
virtctl start testvm
Create an impromptu web server on the VM
Once it is running, use virtctl to access the VM by ssh. Specify the username “cirros” on the virtctl ssh command:
virtctl ssh testvm --username=cirros
Use “gocubsgo” as the password. The Cirros image is a compact linux host running busybox and no package management, so providing a service from it can be tricky. Here is a simple shell script to create a rudimentary web server:
#!/bin/bash while true do ( echo "HTTP/1.0 200 Ok"; echo; echo "netcat webserver on testvm port 80" ) | nc -l -p 80 done
Write that to a file on the server and execute it in the background:
vi webserver.sh sudo sh ./webserver.sh & exit
Alternatively, the while loop may be run at the $ prompt, and the remaining commands run on a separate terminal.
Expose the web server using virtctl
Expose port 80 on the VM using a NodePort:
virtctl expose vmi testvm --name=testvm-http --port=80 --type=NodePort Service testvm-http successfully exposed for vmi testvm
Check the service created by the previous virtctl command:
kubectl get service testvm-http NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE testvm-http NodePort 172.30.191.93 <none> 80:31656/TCP 17s
In this example, 31656 is the NodePort that will correspond to the testvm-http Service’s 8080. Knowing the address of a node in the cluster (wkr0) we can construct a curl command to read the webserver’s output:
curl http://wkr0:31656 netcat webserver on testvm port 80
Mix VM and Pod web servers using a Service
Looking at the testvm-http Service's spec.selector field, we see that it is keying on labels found in the VMI:
kubectl get svc testvm-http -o jsonpath='{.spec.selector}' | jq { "kubevirt.io/domain": "testvm", "kubevirt.io/size": "small" }
If we wanted to try migrating the service to a Pod from the VM, we could use a more general label:
kubectl get pods NAME READY STATUS RESTARTS AGE virt-launcher-testvm-zf9jx 2/2 Running 0 2m kubectl label pod/virt-launcher-testvm-zf9jx app=http
Now we can create a Pod also serving http on port 80 and label it with the same label:
kubectl run testhttp --image=httpd -l app=http
A quick kubectl get will verify that both the testhttp and virt-launcher pods are labeled as expected:
kubectl get po -l app=http NAME READY STATUS RESTARTS AGE testhttp 1/1 Running 0 29s virt-launcher-testvm-zf9jx 2/2 Running 0 3m
Create a service that will target the app=http label:
kubectl apply -f - <<END apiVersion: v1 kind: Service metadata: name: http spec: ports: - port: 8080 targetPort: 80 selector: app: http type: NodePort END
Find the NodePort port:
kubectl get svc http NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE http NodePort 172.30.132.28 <none> 8080:32434/TCP 50s
Access the website a few times:
for i in {0..10}; do curl wkr0:32434; done netcat webserver on testvm port 80 netcat webserver on testvm port 80 <html><body><h1>It works!</h1></body></html> netcat webserver on testvm port 80 netcat webserver on testvm port 80 netcat webserver on testvm port 80 netcat webserver on testvm port 80 <html><body><h1>It works!</h1></body></html> netcat webserver on testvm port 80 <html><body><h1>It works!</h1></body></html> netcat webserver on testvm port 80
As you can see, this gives a mix of the two services.