This sample demonstrates a non-Istio waypoint defined using static Envoy config.
- Create a kind cluster
kind create cluster
- Install Istio with Ambient
istioctl install --set profile=ambient
- Enable ambient for the default namespace.
kubectl label namespace default istio.io/dataplane-mode=ambient --overwrite
- Deploy sleep as a client
kubectl apply -f samples/sleep/sleep.yaml
- Deploy the following manifest.
- httpbin has
istio.io/use-waypoint=static-waypoint
static-waypoint
is a statically configured Envoy proxy.httpbin-headless
just lets us hack around needing EDS for our static envoy.
YAML
cat <<EOF | k apply -f -
---
apiVersion: gateway.networking.k8s.io/v1beta1
kind: GatewayClass
metadata:
name: static-waypoint
annotations:
ambient.istio.io/waypoint-inbound-binding: "PROXY/15088"
spec:
controllerName: nobody.com/none-controller
---
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: static-waypoint
spec:
gatewayClassName: static-waypoint
listeners:
- protocol: PROXY
name: "proxy"
port: 15088
# HACK kubectl edit --subresource status gateway static-waypoint and copy these to status
addresses:
- type: IPAddress
value: 10.96.128.128
status:
addresses:
- type: IPAddress
value: 10.96.128.128
---
apiVersion: v1
kind: ConfigMap
metadata:
name: static-waypoint-config
data:
envoy.yaml: |-
node:
id: waypoint~0.0.0.0~static-waypoint.default~default.svc.cluster.local
cluster: inbound-vip|5201|http|iperf-server.default.svc.cluster.local
admin:
profile_path: /var/lib/istio/data/envoy.prof
address:
socket_address:
address: 127.0.0.1
port_value: 15000
access_log:
- name: envoy.access_loggers.file
typed_config:
'@type': type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog
path: /dev/null
static_resources:
listeners:
- name: inbound_proxy_protocol
address:
socket_address:
address: 0.0.0.0
port_value: 15088
listener_filters:
- name: "proxy_protocol_tlv"
typed_config:
'@type': type.googleapis.com/envoy.extensions.filters.listener.proxy_protocol.v3.ProxyProtocol
allow_requests_without_proxy_protocol: false
rules:
- tlv_type: 0xD0
on_tlv_present:
key: "peer_principal"
- tlv_type: 0xD1
on_tlv_present:
key: "hbone_host"
pass_through_tlvs:
match_type: INCLUDE_ALL
filter_chain_matcher:
matcher_tree:
input:
name: destination_ip
typed_config:
"@type": type.googleapis.com/envoy.extensions.matching.common_inputs.network.v3.DestinationIPInput
prefix_match_map:
map:
# TODO we need the actual vip here
"10.":
action:
name: vip
typed_config:
"@type": type.googleapis.com/google.protobuf.StringValue
value: httpbin
filter_chains:
- name: httpbin
filters:
- name: proxy_protocol_authority
typed_config:
'@type': type.googleapis.com/envoy.extensions.filters.network.set_filter_state.v3.Config
on_new_connection:
- object_key: "io.istio.peer_principal"
factory_key: "envoy.string"
format_string:
text_format_source:
inline_string: "%DYNAMIC_METADATA(envoy.filters.listener.proxy_protocol:peer_principal)%"
- name: envoy.filters.network.http_connection_manager
typed_config:
'@type': type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
stat_prefix: ingress_http
access_log:
- name: envoy.access_loggers.stdout
typed_config:
'@type': type.googleapis.com/envoy.extensions.access_loggers.stream.v3.StdoutAccessLog
http_filters:
- name: envoy.filters.http.grpc_stats
typed_config:
'@type': type.googleapis.com/envoy.extensions.filters.http.grpc_stats.v3.FilterConfig
emit_filter_state: true
stats_for_all_methods: false
- name: envoy.filters.http.fault
typed_config:
'@type': type.googleapis.com/envoy.extensions.filters.http.fault.v3.HTTPFault
- name: envoy.filters.http.cors
typed_config:
'@type': type.googleapis.com/envoy.extensions.filters.http.cors.v3.Cors
- name: envoy.filters.http.router
typed_config:
'@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
route_config:
name: inbound-vip|8000|http|httpbin.default.svc.cluster.local
response_headers_to_add:
- header:
key: "from-waypoint"
value: "static-waypoint"
virtual_hosts:
- name: inbound|http|8000
domains:
- '*'
routes:
- match:
prefix: /
route:
cluster: inbound-vip|8000|http|httpbin.default.svc.cluster.local
decorator:
operation: :8000/*
name: default
clusters:
- name: inbound-vip|8000|http|httpbin.default.svc.cluster.local
type: STRICT_DNS
load_assignment:
cluster_name: inbound-vip|8000|http|httpbin.default.svc.cluster.local
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: httpbin-headless.default.svc
port_value: 8080
---
apiVersion: v1
kind: Service
metadata:
name: static-waypoint
spec:
# HACK static VIP to reference in Gateway
clusterIP: 10.96.128.128
ports:
# HACK this tricks zTunnel into resolving the VIP
- port: 15008
name: hbone
protocol: TCP
selector:
app: static-waypoint
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: static-waypoint
spec:
replicas: 1
selector:
matchLabels:
app: static-waypoint
template:
metadata:
labels:
app: static-waypoint
gateway.networking.k8s.io/gateway-name: static-waypoint
spec:
nodeName: ambient-control-plane
containers:
- name: static-waypoint
image: localhost:5000/proxyv2:sandwich-test
command:
- envoy
- --config-path
- /etc/envoy/envoy.yaml
- --drain-strategy
- immediate
- --local-address-ip-version
- v4
- --file-flush-interval-msec
- "1000"
ports:
- containerPort: 5201
volumeMounts:
- name: static-waypoint-config
mountPath: "/etc/envoy"
volumes:
- name: static-waypoint-config
configMap:
name: static-waypoint-config
---
#
# httpbin service with static VIP + a headless version
#
apiVersion: v1
kind: Service
metadata:
name: httpbin
labels:
app: httpbin
service: httpbin
annotations:
istio.io/use-waypoint: static-waypoint
spec:
# HACK use a static cluster IP that we can reference in envoy config
clusterIP: 10.96.127.1
ports:
- name: http
port: 8000
targetPort: 8080
selector:
app: httpbin
---
apiVersion: v1
kind: Service
metadata:
name: httpbin-headless
labels:
app: httpbin
service: httpbin
spec:
# HACK define a clusterIP service so the static envoy doesn't need EDS
clusterIP: None
ports:
- name: http
port: 8000
targetPort: 8080
selector:
app: httpbin
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: httpbin
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: httpbin
spec:
replicas: 1
selector:
matchLabels:
app: httpbin
version: v1
template:
metadata:
labels:
app: httpbin
version: v1
spec:
serviceAccountName: httpbin
containers:
- image: docker.io/kong/httpbin
imagePullPolicy: IfNotPresent
name: httpbin
# Same as found in Dockerfile's CMD but using an unprivileged port
command:
- gunicorn
- -b
- 0.0.0.0:8080
- httpbin:app
- -k
- gevent
env:
# Tells pipenv to use a writable directory instead of $HOME
- name: WORKON_HOME
value: /tmp
ports:
- containerPort: 8080
EOF
- Hack: Set gateway status addressess since we don't have a controller.
kubectl patch --subresource status gateway static-waypoint --type merge --patch '{"status": {"addresses": [{"value":
"10.96.128.128", "type": "IPAddress"}]}}'
- Finally, send traffic. Notice the header
from-waypoint
.
kubectl exec $(kubectl get po -lapp=sleep -ojsonpath='{.items[0].metadata.name}') -- curl -sS httpbin:8000/get -v