×

You can expose a virtual machine within the cluster or outside the cluster by using a Service object.

About services

A Kubernetes service is an abstract way to expose an application running on a set of pods as a network service. Services allow your applications to receive traffic. Services can be exposed in different ways by specifying a spec.type in the Service object:

ClusterIP

Exposes the service on an internal IP address within the cluster. ClusterIP is the default service type.

NodePort

Exposes the service on the same port of each selected node in the cluster. NodePort makes a service accessible from outside the cluster.

LoadBalancer

Creates an external load balancer in the current cloud (if supported) and assigns a fixed, external IP address to the service.

For on-premise clusters, you can configure a load-balancing service by deploying the MetalLB Operator.

Dual-stack support

If IPv4 and IPv6 dual-stack networking is enabled for your cluster, you can create a service that uses IPv4, IPv6, or both, by defining the spec.ipFamilyPolicy and the spec.ipFamilies fields in the Service object.

The spec.ipFamilyPolicy field can be set to one of the following values:

SingleStack

The control plane assigns a cluster IP address for the service based on the first configured service cluster IP range.

PreferDualStack

The control plane assigns both IPv4 and IPv6 cluster IP addresses for the service on clusters that have dual-stack configured.

RequireDualStack

This option fails for clusters that do not have dual-stack networking enabled. For clusters that have dual-stack configured, the behavior is the same as when the value is set to PreferDualStack. The control plane allocates cluster IP addresses from both IPv4 and IPv6 address ranges.

You can define which IP family to use for single-stack or define the order of IP families for dual-stack by setting the spec.ipFamilies field to one of the following array values:

  • [IPv4]

  • [IPv6]

  • [IPv4, IPv6]

  • [IPv6, IPv4]

Exposing a virtual machine as a service

Create a ClusterIP, NodePort, or LoadBalancer service to connect to a running virtual machine (VM) from within or outside the cluster.

Procedure
  1. Edit the VirtualMachine manifest to add the label for service creation:

    apiVersion: kubevirt.io/v1
    kind: VirtualMachine
    metadata:
      name: vm-ephemeral
      namespace: example-namespace
    spec:
      running: false
      template:
        metadata:
          labels:
            special: key (1)
    # ...
    1 Add the label special: key in the spec.template.metadata.labels section.

    Labels on a virtual machine are passed through to the pod. The special: key label must match the label in the spec.selector attribute of the Service manifest.

  2. Save the VirtualMachine manifest file to apply your changes.

  3. Create a Service manifest to expose the VM:

    apiVersion: v1
    kind: Service
    metadata:
      name: vmservice (1)
      namespace: example-namespace (2)
    spec:
      externalTrafficPolicy: Cluster (3)
      ports:
      - nodePort: 30000 (4)
        port: 27017
        protocol: TCP
        targetPort: 22 (5)
      selector:
        special: key (6)
      type: NodePort (7)
    1 The name of the Service object.
    2 The namespace where the Service object resides. This must match the metadata.namespace field of the VirtualMachine manifest.
    3 Optional: Specifies how the nodes distribute service traffic that is received on external IP addresses. This only applies to NodePort and LoadBalancer service types. The default value is Cluster which routes traffic evenly to all cluster endpoints.
    4 Optional: When set, the nodePort value must be unique across all services. If not specified, a value in the range above 30000 is dynamically allocated.
    5 Optional: The VM port to be exposed by the service. It must reference an open port if a port list is defined in the VM manifest. If targetPort is not specified, it takes the same value as port.
    6 The reference to the label that you added in the spec.template.metadata.labels stanza of the VirtualMachine manifest.
    7 The type of service. Possible values are ClusterIP, NodePort and LoadBalancer.
  4. Save the Service manifest file.

  5. Create the service by running the following command:

    $ oc create -f <service_name>.yaml
  6. Start the VM. If the VM is already running, restart it.

Verification
  1. Query the Service object to verify that it is available:

    $ oc get service -n example-namespace
    Example output for ClusterIP service
    NAME        TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)     AGE
    vmservice   ClusterIP   172.30.3.149   <none>        27017/TCP   2m
    Example output for NodePort service
    NAME        TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)            AGE
    vmservice   NodePort    172.30.232.73   <none>       27017:30000/TCP    5m
    Example output for LoadBalancer service
    NAME        TYPE            CLUSTER-IP     EXTERNAL-IP                    PORT(S)           AGE
    vmservice   LoadBalancer    172.30.27.5   172.29.10.235,172.29.10.235     27017:31829/TCP   5s
  2. Choose the appropriate method to connect to the virtual machine:

    • For a ClusterIP service, connect to the VM from within the cluster by using the service IP address and the service port. For example:

      $ ssh fedora@172.30.3.149 -p 27017
    • For a NodePort service, connect to the VM by specifying the node IP address and the node port outside the cluster network. For example:

      $ ssh fedora@$NODE_IP -p 30000
    • For a LoadBalancer service, use the vinagre client to connect to your virtual machine by using the public IP address and port. External ports are dynamically allocated.