An Istio VirtualService is applied with no `gateways` field set. Which traffic does it govern, and what has to change for that same VirtualService to route requests arriving at an Istio ingress Gateway?
answer
- omitting the field is not neutral
- a reserved word meaning all sidecars
- the listener has no routes of its own
- listing one replaces the default
- hostnames must overlap on both sides
basics
~20 sWith no gateways field, a VirtualService defaults to the reserved value mesh, so it applies only to traffic between sidecars inside the mesh. To take effect at the edge it must list the Istio Gateway resource by name, and its hosts must overlap the hostnames that Gateway serves.
solid answer
~50 sOmitting `gateways` is not the same as leaving it open: it defaults to the reserved name **`mesh`**, meaning every sidecar in the mesh, and nothing at the edge. An Istio **Gateway** resource describes the ports, protocols and hostnames an ingress proxy accepts, selected by labels through its `selector` — but it carries no routing rules of its own. Binding is explicit: the VirtualService must name that Gateway in its `gateways` list, and the VirtualService's `hosts` must intersect the `hosts` in the Gateway's `servers`. Two details bite people. Listing only the gateway name **replaces** the default, so in-mesh callers of the same host stop matching — you usually want `gateways: ["mesh", "my-gateway"]`. And a Gateway in another namespace must be referenced as `namespace/name`, not by bare name. The symptom of getting any of this wrong is a 404 from the ingress proxy itself, with the application never seeing the request.
code
yaml · 17 linesapiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: shop
namespace: shop
spec:
hosts:
- shop.example.com
gateways:
- mesh # keep east-west routing
- istio-system/web-gateway # add edge routing, qualified
http:
- route:
- destination:
host: frontend.shop.svc.cluster.local
port:
number: 8080go deeper
Remember that a VirtualService with no gateways field defaults to the reserved value mesh, so it only affects sidecar-to-sidecar traffic and does nothing at the ingress.
Explain the whole binding chain: the Gateway declares ports, protocols and hostnames and selects an ingress workload, and the VirtualService must reference it by namespace-qualified name with intersecting hosts.
Diagnose an edge 404 methodically — selector, port, gateway reference, host intersection, destination — and check what the ingress proxy was actually programmed with rather than trusting the manifests.
Own the shared-ingress contract: which namespaces may bind to which hostnames via the host qualifier, whether edge and in-mesh routing share a resource, and how hostname claims are prevented from colliding across teams.
## Two resources, one binding The Istio edge is described by a pair of resources that do genuinely different jobs. The **Gateway** is the listener description. It says which ingress workload is being configured (through `selector`, matching labels on the ingress proxy's pods), which ports and protocols it accepts, which hostnames it will serve, and how TLS is handled for each server: ```yaml apiVersion: networking.istio.io/v1beta1 kind: Gateway metadata: name: web-gateway namespace: istio-system spec: selector: istio: ingressgateway servers: - port: number: 443 name: https protocol: HTTPS tls: mode: SIMPLE credentialName: web-tls hosts: - shop.example.com ``` A Gateway on its own accepts connections and then has nowhere to send them. It contains **no routes**. The routing lives, as always, in a VirtualService — and the VirtualService has to say that it applies here. ## The default is `mesh`, not "everywhere" `spec.gateways` on a VirtualService is a list, and when you omit it Istio treats it as `["mesh"]`. `mesh` is a reserved name meaning *all sidecar proxies in the mesh*. So an omitted `gateways` field gives you east-west routing only: service-to-service calls inside the cluster obey the rules, and requests arriving at the ingress do not. To serve edge traffic, list the Gateway: ```yaml spec: hosts: - shop.example.com gateways: - istio-system/web-gateway http: - route: - destination: {host: frontend, port: {number: 8080}} ``` ## The replacement trap Writing `gateways: ["istio-system/web-gateway"]` **replaces** the default rather than adding to it. If in-mesh services also call this host by the same name, their traffic no longer matches any rule in this VirtualService, and behaviour silently changes — canary weights stop applying east-west, or a rewrite stops happening. When one VirtualService is meant to govern both directions, list both: ```yaml gateways: - mesh - istio-system/web-gateway ``` That said, edge routing and in-mesh routing usually want different hostnames and different rules. Splitting them into two VirtualServices is often cleaner than one resource trying to serve both. ## Namespaces and qualified names Gateways commonly live in the ingress namespace (`istio-system` in a default installation) while the VirtualService lives with the application. A bare name in `gateways` resolves in the **VirtualService's own** namespace, so referencing a Gateway elsewhere requires the `namespace/name` form. A silently non-matching reference is one of the two most common causes of edge 404s. The Gateway's `servers[].hosts` may itself be namespace-qualified — `"*/shop.example.com"` allows a VirtualService in any namespace to bind for that host, while `"./shop.example.com"` restricts binding to the Gateway's own namespace. That is the control an ingress owner uses to decide which teams may attach routes to a shared hostname. ## Hosts must intersect Even with the Gateway correctly referenced, the VirtualService's `hosts` must overlap the Gateway server's `hosts`. A Gateway serving `shop.example.com` and a VirtualService declaring `hosts: ["www.example.com"]` bind to nothing useful, and the ingress answers 404. Wildcards are allowed on both sides, and `"*"` on the Gateway accepts anything — convenient in a demo, and a poor idea on a shared ingress, because any team can then claim any hostname. ## Diagnosing an edge 404 When requests reach the ingress and come back 404 without the application logging anything, work through the binding chain in order: does the Gateway's `selector` actually match the ingress pods' labels; is the port and protocol right; does the VirtualService reference the Gateway with the correct `namespace/name`; do the hostnames intersect; and does the destination resolve. Inspecting the ingress proxy's routes with `istioctl proxy-config route` on the ingress pod shows whether the route was ever programmed — an empty or default-only route table means the binding failed, not the routing.
- Your VirtualService lives in the application namespace and the Gateway in istio-system. What must the gateways entry look like?`istio-system/web-gateway` — the `namespace/name` form. A bare `web-gateway` resolves in the VirtualService's own namespace, finds nothing, and the binding silently fails. The ingress then answers 404 for the hostname while the application logs stay empty, which is exactly why this is worth checking first.
- How does the owner of a shared ingress control which teams may attach routes to a hostname?Through the namespace qualifier on the Gateway's `servers[].hosts`. `"./shop.example.com"` allows binding only from the Gateway's own namespace, while `"*/shop.example.com"` allows any namespace. Combined with not using a bare `"*"` host, that stops one team from claiming a hostname another team owns.
- You added the gateway to the gateways list and now in-mesh callers behave differently. What happened?The list replaced the implicit `mesh` default rather than adding to it, so sidecar-originated calls to that host no longer match any rule in the VirtualService. Add `mesh` back explicitly, or split edge and in-mesh routing into two VirtualServices with the rules each direction actually needs.
saying these in an interview costs you the question
- Thinks an omitted gateways field means all traffic
- Believes the Gateway resource itself carries routing rules
- References a cross-namespace Gateway by bare name
- Forgets the VirtualService hosts must match the Gateway hosts
- Assumes adding a gateway keeps mesh routing automatically