Skip to main content

Documentation Index

Fetch the complete documentation index at: https://notes.kodekloud.com/llms.txt

Use this file to discover all available pages before exploring further.

This guide shows how to bring an external workload into an Istio service mesh using a ServiceEntry and a VirtualService — without changing the mesh-wide outbound policy. This pattern is useful when the external workload is outside the Kubernetes cluster (for example, an internal EC2 instance or an on-premises web server) and you want Istio to capture and control traffic to it. What you will learn:
  • Confirm the cluster and Istio environment
  • Create a ServiceEntry for an external host
  • Create a VirtualService to instruct Istio how to route traffic to that ServiceEntry
  • Ensure the client pod has an Envoy sidecar so Istio can intercept outbound traffic
Keywords: Istio ServiceEntry, VirtualService, external workload, Envoy sidecar, mesh-external, static endpoint

Prerequisites

RequirementPurpose / Example
Istio installedistioctl version (example 1.26.3)
External NGINX web appReachable at myapp.com (resolved via /etc/hosts to a static IP)
kubectl accessTo create resources and run test pods
Useful quick-check commands:
kubectl get pods -A
istioctl version
Example istioctl version output:
client version: 1.26.3
control plane version: 1.26.3
Verify the external app resolves and responds from the control plane host (this demo uses an /etc/hosts override):
curl myapp.com
Example truncated HTML response:
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
...
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p>
...
</html>
Example local DNS override used in this demo:
cat /etc/hosts
# example:
# 10.0.0.6 docker-registry-mirror.kodekloud.com
# 127.0.1.1 controlplane controlplane
# 192.168.121.2 myapp.com
Note: replace 192.168.121.2 below with the IP address your myapp.com resolves to.

Step 1 — Create a ServiceEntry

A ServiceEntry tells Istio about services that exist outside the mesh. For a fixed IP endpoint use resolution: STATIC. Create a file named se.yaml:
apiVersion: networking.istio.io/v1beta1
kind: ServiceEntry
metadata:
  name: myapp-service-entry
spec:
  hosts:
  - myapp.com
  location: MESH_EXTERNAL
  ports:
  - number: 80
    name: http
    protocol: HTTP
  resolution: STATIC
  endpoints:
  - address: 192.168.121.2
Apply the ServiceEntry and confirm it was created:
kubectl apply -f se.yaml
kubectl get serviceentries.networking.istio.io
Example output:
NAME                   HOSTS            LOCATION      RESOLUTION   AGE
myapp-service-entry    ["myapp.com"]    MESH_EXTERNAL STATIC       30s
This exposes myapp.com:80 to the mesh and instructs Istio to resolve myapp.com to the static IP 192.168.121.2.

Step 2 — Run a test client pod and try curling the external host

Start a simple pod that includes curl. The official nginx image may not include curl; use an image such as curlimages/curl and keep the pod alive with sleep:
kubectl run test --image=curlimages/curl --restart=Never --command -- sleep 3600
kubectl get pods
Example:
NAME   READY   STATUS    RESTARTS   AGE
test   1/1     Running   0          30s
From inside the test pod, attempt to curl the external host:
kubectl exec test -- curl -sS -D - myapp.com -o /dev/null
If the test pod does not have an Istio sidecar injected (no Envoy), you might see an unexpected intermediate response such as an HTTP 302 from an upstream gateway or proxy:
Response Header
# HTTP/1.1 302 Found
# ...
Or you may see the small HTML 302 page:
<html>
<head><title>302 Found</title></head>
<body>
<center><h1>302 Found</h1></center>
<hr><center>stgw</center>
</body>
</html>
Why? Although the ServiceEntry exists, Istio only applies mesh routing (VirtualService handling) when the client pod’s outbound traffic is intercepted by the Envoy sidecar. If the pod is running in a namespace without Istio automatic sidecar injection enabled, Envoy is not present and Istio cannot manage that pod’s outbound traffic.
Make sure the client pod has an Envoy sidecar injected. If the pod is in a namespace without Istio injection enabled, Istio features (VirtualService routing and ServiceEntry handling through the proxy) will not be applied to that pod’s outbound traffic.

Step 3 — Create a VirtualService to route traffic to the ServiceEntry

A VirtualService tells Istio how to route requests for specified hosts. Create vs.yaml:
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: myapp-vs
spec:
  hosts:
  - myapp.com
  http:
  - route:
    - destination:
        host: myapp.com
        port:
          number: 80
Apply the VirtualService and list virtual services:
kubectl apply -f vs.yaml
kubectl get virtualservice
Example output:
NAME       GATEWAYS   HOSTS             AGE
myapp-vs              ["myapp.com"]     4s
Although this VirtualService appears to route myapp.com to myapp.com:80 (redundant looking), it is important: it instructs Istio how to process and forward requests for myapp.com. The destination host myapp.com is then resolved by the ServiceEntry to the external IP.

Step 4 — Ensure the client pod has an Istio sidecar

If the test pod was created in a namespace without sidecar injection, Istio will analyze and warn:
istioctl analyze
Example analysis result:
Info [IST0102] (Namespace default) The namespace is not enabled for Istio injection. Run 'kubectl label namespace default istio-injection=enabled' to enable it, or 'kubectl label namespace default istio-injection=disabled' to explicitly mark it as not needing injection.
Enable automatic injection for the namespace (example shows the default namespace):
kubectl label namespace default istio-injection=enabled --overwrite
Recreate the test pod so it will be injected with the Envoy sidecar:
kubectl delete pod test
kubectl run test --image=curlimages/curl --restart=Never --command -- sleep 3600
kubectl get pods
You should see the pod transition and then report READY 2/2:
# NAME   READY   STATUS    RESTARTS   AGE
# test   2/2     Running   0          1m
2/2 indicates the application container plus the Envoy sidecar are running.

Step 5 — Retry the curl from the injected pod

With the Envoy sidecar present, Istio will capture and route outbound traffic according to the ServiceEntry and VirtualService. Run:
kubectl exec test -- curl -sS myapp.com
You should receive the full NGINX page:
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
...
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p>
...
</html>
This confirms Istio is intercepting the traffic and routing the request to the external endpoint specified in the ServiceEntry.

Troubleshooting & Tips

  • If the external service listens on a different port (e.g., 9090), update the ServiceEntry ports and endpoints accordingly.
  • For DNS-resolvable external services use resolution: DNS and omit endpoints — Istio will resolve the host dynamically.
  • For fixed internal IPs (such as an on-premise box), resolution: STATIC with endpoints is appropriate.
  • If you prefer manual sidecar injection, use istioctl kube-inject or the sidecar.istio.io/inject annotation on pod spec rather than enabling namespace-wide automatic injection.
  • Use istioctl analyze to check for common configuration issues and hints.
  • Remember to replace the demo IP 192.168.121.2 with the correct IP for your environment.

Quick reference commands

ActionCommand
Apply ServiceEntrykubectl apply -f se.yaml
Apply VirtualServicekubectl apply -f vs.yaml
Run test podkubectl run test --image=curlimages/curl --restart=Never --command -- sleep 3600
Exec into pod and curlkubectl exec test -- curl -sS myapp.com
Enable namespace injectionkubectl label namespace default istio-injection=enabled --overwrite
Analyze Istio configistioctl analyze

This exercise is useful preparation for the Istio Certified Associate (ICA) exam and real-world scenarios where you need to bring external services under Istio control. Try it in a lab environment to reinforce the steps.

Watch Video

Practice Lab