Skip to content

Networking

Every pod on a GRN.CLOUD cluster has its own network interface and its own IP address on a single flat cluster network. Pods reach each other directly at those addresses, with no network address translation applied in either direction, whether the sending and receiving pods are on the same node or on nodes in different availability zones.

Two properties of that network shape everything else on this page:

  • A pod address is not stable. It is assigned when the pod is scheduled and released when the pod is replaced, and a scaled workload has one address per replica. To reach a workload at a fixed address, put a Service in front of it and address the Service.
  • The network is open until you close it. Any pod can open a connection to any other pod, and any client that can route to a Service can use it, until a NetworkPolicy selects those pods.

Firewalling, load balancing, VPN termination, multi-cluster connectivity and VM networks are all objects in the cluster API, so network configuration lives in Git next to the application it belongs to, is applied by the same pipeline, and is portable to any conformant cluster.

Default-deny network policy

By default, every pod in a project accepts connections from any other pod and from any network endpoint that can route to it. A NetworkPolicy changes that for the pods its podSelector matches: once a pod is selected by at least one policy, it accepts only the connections that at least one of those policies allows. A pod that no policy selects stays fully reachable.

Policies are additive, so the usual pattern is to select every pod with an empty podSelector, deny by default, and then add narrower policies that allow what each workload needs. Most other pages in these docs assume that shape:

default-deny-egress.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-egress
spec:
  podSelector: {}
  policyTypes: ["Egress"]

A default-deny egress policy also blocks traffic inside the namespace

Unlike a security group, NetworkPolicy has no implicit allowance for traffic that stays within the namespace. A default-deny-egress policy with an empty podSelector selects every pod in the project, so it blocks connections between your own pods, and it blocks DNS resolution to kube-dns. Add a self-referencing egress rule so members of the namespace can still reach each other:

allow-intra-namespace-egress.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-intra-namespace-egress
spec:
  podSelector: {}
  policyTypes: ["Egress"]
  egress:
    - to:
        - podSelector: {}

Firewalls

A firewall is a NetworkPolicy. In the console they live under WebHosting > Networking > Firewalls, one row per policy, showing which pods it applies to.

Create Firewall opens a guided form: pick the Service you want to protect, the port and protocol, and who may reach it - this project only, anywhere in the cluster, or the public internet. The form derives the pod selector from the Service you chose, which is the part most hand-written policies get wrong.

The equivalent object, opening one port to your app and leaving everything else on those pods closed:

allow-myapp-http.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-myapp-http
  namespace: <your-project>
spec:
  podSelector:
    matchLabels:
      app: myapp
  policyTypes:
  - Ingress
  ingress:
  - from: []
    ports:
    - protocol: TCP
      port: 8080

from: [] allows any source. To restrict a backend so only your own pods can reach it - a database that should never be reachable from outside - swap it for a podSelector:

  ingress:
  - from:
    - podSelector: {}
    ports:
    - protocol: TCP
      port: 5432

If a service stops responding after you add a firewall

Check that you allowed the port your Route or LoadBalancer forwards to. Opening a different port from the one exposed is the most common cause.

An empty podSelector: {} applies to every pod in the project - that is how you build a namespace-wide default deny, then layer specific allows on top. Policies cover inbound traffic only unless you add policyTypes: [Egress] and an egress: block.

Load balancers

WebHosting > Networking > LoadBalancers exposes an application outside the cluster, either as a website over HTTPS or as raw TCP/UDP.

Websites do not appear in this list

The list shows Service objects of type LoadBalancer. Exposing an app as a website creates a Route instead, which does not get a row here - find it under Administration > Domains, or with oc get routes.

Create LoadBalancer walks through it: choose a Service in your project, and the console inspects its ports to guess whether you are publishing a website or raw traffic, pre-filling the type accordingly.

For a website you supply a hostname - either a subdomain of apps.grn.cloud or your own domain - and the platform issues the TLS certificate automatically. Give it a minute or two on first creation.

myapp-route.yaml
apiVersion: route.openshift.io/v1
kind: Route
metadata:
  name: myapp
  namespace: <your-project>
spec:
  host: myapp.apps.grn.cloud
  to:
    kind: Service
    name: myapp
  port:
    targetPort: http
  tls:
    termination: edge
    insecureEdgeTerminationPolicy: Redirect

Using your own domain means pointing a CNAME at your project's ingress address before creating the Route - the certificate cannot be issued until DNS resolves.

For anything that does not speak HTTP - a database, a game server, a custom protocol - a Service of type LoadBalancer gets a public address instead:

myapp-tcp.yaml
apiVersion: v1
kind: Service
metadata:
  name: myapp-tcp
  namespace: <your-project>
spec:
  type: LoadBalancer
  selector:
    app: myapp
  ports:
  - name: tcp
    port: 8080
    targetPort: 8080
    protocol: TCP

The External IP column fills in once the platform allocates an address.

What this section will cover

  • Private subnets and user-defined networks for VMs
  • VPN and site-to-site connectivity
  • Multi-cluster networking
  • Gateway API

How to

Step-by-step guides for each of these, in the console and as YAML: