Skip to content

Commit abf9d29

Browse files
authored
Wpb 22439 fix helm operations coturn sftd (#858)
* fix: wpb-22439 make using daemonset with nodePort for ingress-nginx-controller default for prod and make load-balancer an example * fix: wpb-22439 add changelog and fix cd.sh for ingress-nginx-controller file change * fix: wpb-23462: add metrics config for ingress-nginx-controller/prod-values * fix: wpb-22439 add comment for replica-count management in coturn and sftd * fix: wpb-22439 fix cd.sh for ingress-nginx-controller file change * fix: wpb-22439: deprecating offline-helm.sh for bin/helm-operations.sh * fix: wpb-22439: update wiab-staging.md and postgresql-cluster.md for helm-operations.sh reference
1 parent b4341f5 commit abf9d29

12 files changed

Lines changed: 269 additions & 75 deletions

bin/helm-operations.sh

Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
#!/usr/bin/env bash
2+
# shellcheck disable=SC2087
3+
set -Eeo pipefail
4+
5+
# Read values from environment variables with defaults
6+
BASE_DIR="/wire-server-deploy"
7+
TARGET_SYSTEM="example.dev"
8+
CERT_MASTER_EMAIL="certmaster@${TARGET_SYSTEM}"
9+
10+
# this IP should match the DNS A record value for TARGET_SYSTEM
11+
# assuming it to be the public address used by clients to reach public Address
12+
HOST_IP=""
13+
if [ -z "$HOST_IP" ]; then
14+
HOST_IP=$(wget -qO- https://api.ipify.org)
15+
fi
16+
17+
# picking a node for calling traffic (3rd kube worker node)
18+
CALLING_NODE=$(kubectl get nodes --no-headers | tail -n 1 | awk '{print $1}')
19+
if [[ -z "$CALLING_NODE" ]]; then
20+
echo "Error: could not determine the last kube worker node via kubectl"
21+
exit 1
22+
fi
23+
24+
# Creates values.yaml from prod-values.example.yaml and secrets.yaml from prod-secrets.example.yaml
25+
# Works on all chart directories in $BASE_DIR/values/
26+
process_values() {
27+
28+
ENV=$1
29+
TYPE=$2
30+
charts=(fake-aws smtp rabbitmq databases-ephemeral reaper wire-server webapp account-pages team-settings smallstep-accomp ingress-nginx-controller nginx-ingress-services coturn sftd cert-manager)
31+
32+
if [[ "$ENV" != "prod" ]] || [[ -z "$TYPE" ]] ; then
33+
echo "Error: This function only supports prod deployments with TYPE as values or secrets. ENV must be 'prod', got: '$ENV' and '$TYPE'"
34+
exit 1
35+
fi
36+
timestp=$(date +"%Y%m%d_%H%M%S")
37+
38+
for chart in "${charts[@]}"; do
39+
chart_dir="$BASE_DIR/values/$chart"
40+
if [[ -d "$chart_dir" ]]; then
41+
if [[ -f "$chart_dir/${ENV}-${TYPE}.example.yaml" ]]; then
42+
if [[ ! -f "$chart_dir/${TYPE}.yaml" ]]; then
43+
cp "$chart_dir/${ENV}-${TYPE}.example.yaml" "$chart_dir/${TYPE}.yaml"
44+
echo "Used template ${ENV}-${TYPE}.example.yaml to create $chart_dir/${TYPE}.yaml"
45+
else
46+
echo "$chart_dir/${TYPE}.yaml already exists, archiving it and creating a new one."
47+
mv "$chart_dir/${TYPE}.yaml" "$chart_dir/${TYPE}.yaml.bak.$timestp"
48+
cp "$chart_dir/${ENV}-${TYPE}.example.yaml" "$chart_dir/${TYPE}.yaml"
49+
fi
50+
fi
51+
fi
52+
done
53+
}
54+
55+
# selectively setting values of following charts which requires additional values
56+
# wire-server, webapp, team-settings, account-pages, nginx-ingress-services, sftd and coturn
57+
configure_values() {
58+
59+
TEMP_DIR=$(mktemp -d)
60+
trap 'rm -rf $TEMP_DIR' EXIT
61+
62+
# to find IP address of calling NODE
63+
CALLING_NODE_IP=$(kubectl get node "$CALLING_NODE" -o jsonpath='{.status.addresses[?(@.type=="InternalIP")].address}')
64+
65+
# Fixing the hosts with TARGET_SYSTEM and setting the turn server
66+
sed -e "s/example.com/$TARGET_SYSTEM/g" \
67+
"$BASE_DIR/values/wire-server/values.yaml" > "$TEMP_DIR/wire-server-values.yaml"
68+
69+
# fixing the turnStatic values
70+
yq eval -i ".brig.turnStatic.v2 = [\"turn:$HOST_IP:3478\", \"turn:$HOST_IP:3478?transport=tcp\"]" "$TEMP_DIR/wire-server-values.yaml"
71+
72+
# Fixing the hosts in webapp team-settings and account-pages charts
73+
for chart in webapp team-settings account-pages; do
74+
sed "s/example.com/$TARGET_SYSTEM/g" "$BASE_DIR/values/$chart/values.yaml" > "$TEMP_DIR/$chart-values.yaml"
75+
done
76+
77+
# Setting certManager and DNS records
78+
sed -e 's/useCertManager: false/useCertManager: true/g' \
79+
-e "/certmasterEmail:$/s/certmasterEmail:/certmasterEmail: $CERT_MASTER_EMAIL/" \
80+
-e "s/example.com/$TARGET_SYSTEM/" \
81+
"$BASE_DIR/values/nginx-ingress-services/values.yaml" > "$TEMP_DIR/nginx-ingress-services-values.yaml"
82+
83+
# Fixing SFTD hosts and setting the cert-manager to http01
84+
sed -e "s/webapp.example.com/webapp.$TARGET_SYSTEM/" \
85+
-e "s/sftd.example.com/sftd.$TARGET_SYSTEM/" \
86+
-e 's/name: letsencrypt-prod/name: letsencrypt-http01/' \
87+
"$BASE_DIR/values/sftd/values.yaml" > "$TEMP_DIR/sftd-values.yaml"
88+
89+
# Setting coturn node IP values
90+
yq eval -i ".coturnTurnListenIP = \"$CALLING_NODE_IP\"" "$BASE_DIR/values/coturn/values.yaml"
91+
yq eval -i ".coturnTurnRelayIP = \"$CALLING_NODE_IP\"" "$BASE_DIR/values/coturn/values.yaml"
92+
yq eval -i ".coturnTurnExternalIP = \"$HOST_IP\"" "$BASE_DIR/values/coturn/values.yaml"
93+
94+
# Compare and copy files if different
95+
for file in wire-server-values.yaml webapp-values.yaml team-settings-values.yaml account-pages-values.yaml \
96+
nginx-ingress-services-values.yaml sftd-values.yaml; do
97+
if ! cmp -s "$TEMP_DIR/$file" "$BASE_DIR/values/${file%-values.yaml}/values.yaml"; then
98+
cp "$TEMP_DIR/$file" "$BASE_DIR/values/${file%-values.yaml}/values.yaml"
99+
echo "Updating $BASE_DIR/values/${file%-values.yaml}/values.yaml"
100+
fi
101+
done
102+
103+
}
104+
105+
deploy_charts() {
106+
107+
local charts=("$@")
108+
echo "Following charts will be deployed: ${charts[*]}"
109+
110+
for chart in "${charts[@]}"; do
111+
chart_dir="$BASE_DIR/charts/$chart"
112+
values_file="$BASE_DIR/values/$chart/values.yaml"
113+
secrets_file="$BASE_DIR/values/$chart/secrets.yaml"
114+
115+
if [[ ! -d "$chart_dir" ]]; then
116+
echo "Error: Chart directory $chart_dir does not exist. Exiting fix the charts"
117+
exit 1
118+
fi
119+
120+
if [[ ! -f "$values_file" ]]; then
121+
echo "Warning: Values file $values_file does not exist. Deploying without values."
122+
values_file=""
123+
fi
124+
125+
if [[ ! -f "$secrets_file" ]]; then
126+
secrets_file=""
127+
fi
128+
129+
helm_command="helm upgrade --install --wait --timeout=15m0s $chart $chart_dir"
130+
131+
if [[ -n "$values_file" ]]; then
132+
helm_command+=" --values $values_file"
133+
fi
134+
135+
if [[ -n "$secrets_file" ]]; then
136+
helm_command+=" --values $secrets_file"
137+
fi
138+
139+
# handle wire-server to inject PostgreSQL password from databases-ephemeral
140+
if [[ "$chart" == "wire-server" ]]; then
141+
142+
echo "Retrieving PostgreSQL password from databases-ephemeral for wire-server deployment..."
143+
if kubectl get secret wire-postgresql-secret &>/dev/null; then
144+
# Usage: sync-k8s-secret-to-wire-secrets.sh <secret-name> <secret-key> <yaml-file> <yaml-path's>
145+
"$BASE_DIR/bin/sync-k8s-secret-to-wire-secrets.sh" \
146+
wire-postgresql-secret password \
147+
"$BASE_DIR/values/wire-server/secrets.yaml" \
148+
.brig.secrets.pgPassword .galley.secrets.pgPassword
149+
else
150+
echo "⚠️ Warning: PostgreSQL secret 'wire-postgresql-secret' not found, skipping secret sync"
151+
echo " Make sure databases-ephemeral chart is deployed before wire-server"
152+
fi
153+
fi
154+
155+
echo "Deploying $chart as $helm_command"
156+
eval "$helm_command"
157+
done
158+
159+
# display running pods post deploying all helm charts in default namespace
160+
kubectl get pods --sort-by=.metadata.creationTimestamp
161+
}
162+
163+
deploy_cert_manager() {
164+
165+
kubectl get namespace cert-manager-ns || kubectl create namespace cert-manager-ns
166+
helm upgrade --install -n cert-manager-ns cert-manager "$BASE_DIR/charts/cert-manager" --values "$BASE_DIR/values/cert-manager/values.yaml"
167+
168+
# display running pods
169+
kubectl get pods --sort-by=.metadata.creationTimestamp -n cert-manager-ns
170+
}
171+
172+
deploy_calling_services() {
173+
174+
echo "Deploying sftd and coturn"
175+
# select the node to deploy sftd
176+
kubectl annotate node "$CALLING_NODE" wire.com/external-ip="$HOST_IP" --overwrite
177+
helm upgrade --install sftd "$BASE_DIR/charts/sftd" --set "nodeSelector.kubernetes\\.io/hostname=$CALLING_NODE" --values "$BASE_DIR/values/sftd/values.yaml"
178+
179+
kubectl annotate node "$CALLING_NODE" wire.com/external-ip="$HOST_IP" --overwrite
180+
helm upgrade --install coturn "$BASE_DIR/charts/coturn" --set "nodeSelector.kubernetes\\.io/hostname=$CALLING_NODE" --values "$BASE_DIR/values/coturn/values.yaml" --values "$BASE_DIR/values/coturn/secrets.yaml"
181+
}
182+
183+
main() {
184+
# Create prod-values.example.yaml to values.yaml and take backup
185+
process_values "prod" "values"
186+
# Create prod-secrets.example.yaml to secrets.yaml and take backup
187+
process_values "prod" "secrets"
188+
189+
# configure chart specific variables for each chart in values.yaml file
190+
configure_values
191+
192+
# deploying with external datastores, useful for prod setup
193+
deploy_charts cassandra-external elasticsearch-external minio-external postgresql-external fake-aws smtp rabbitmq-external databases-ephemeral reaper wire-server webapp account-pages team-settings smallstep-accomp ingress-nginx-controller
194+
195+
# deploying cert manager to issue certs, by default letsencrypt-http01 issuer is configured
196+
deploy_cert_manager
197+
198+
# nginx-ingress-services chart needs cert-manager to be deployed
199+
deploy_charts nginx-ingress-services
200+
201+
# deploying sft and coturn services
202+
# not implemented yet
203+
deploy_calling_services
204+
205+
# print status of certs
206+
kubectl get certificate
207+
}
208+
209+
main

bin/offline-deploy.sh

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,10 @@ echo "Syncing PostgreSQL password from Kubernetes secret..."
4646
sudo docker run --network=host -v $PWD:/wire-server-deploy $WSD_CONTAINER ./bin/sync-k8s-secret-to-wire-secrets.sh \
4747
wire-postgresql-external-secret \
4848
password \
49-
values/wire-server/secrets.yaml \
49+
values/wire-server/prod-secrets.example.yaml \
5050
.brig.secrets.pgPassword \
5151
.galley.secrets.pgPassword \
5252
.spar.secrets.pgPassword \
5353
.gundeck.secrets.pgPassword
5454

55-
56-
sudo docker run --network=host -v $PWD:/wire-server-deploy $WSD_CONTAINER ./bin/offline-helm.sh
55+
sudo docker run --network=host -v $PWD:/wire-server-deploy $WSD_CONTAINER ./bin/helm-operations.sh
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#!/usr/bin/env bash
2-
2+
# this script has been deprecated in favour to helm-operations.sh, which is closer to all value changes in helm values files.
33
set -euo pipefail
44
set -x
55

bin/offline-secrets.sh

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,9 @@ mls_ecdsa_p256_key="$(generate_mls_key -algorithm ec -pkeyopt ec_paramgen_curve:
3434
mls_ecdsa_p384_key="$(generate_mls_key -algorithm ec -pkeyopt ec_paramgen_curve:P-384)"
3535
mls_ecdsa_p521_key="$(generate_mls_key -algorithm ec -pkeyopt ec_paramgen_curve:P-521)"
3636

37-
if [[ ! -f $VALUES_DIR/wire-server/secrets.yaml ]]; then
38-
echo "Writing $VALUES_DIR/wire-server/secrets.yaml"
39-
cat <<EOF > $VALUES_DIR/wire-server/secrets.yaml
37+
38+
echo "Writing $VALUES_DIR/wire-server/prod-secrets.example.yaml"
39+
cat <<EOF > $VALUES_DIR/wire-server/prod-secrets.example.yaml
4040
brig:
4141
secrets:
4242
pgPassword: verysecurepassword
@@ -115,7 +115,13 @@ background-worker:
115115
password: guest
116116
EOF
117117

118-
fi
118+
echo "Writing $VALUES_DIR/coturn/prod-secrets.example.yaml"
119+
cat <<EOF > $VALUES_DIR/coturn/prod-secrets.example.yaml
120+
secrets:
121+
zrestSecrets:
122+
- "$zrest"
123+
EOF
124+
119125

120126
if [[ ! -f $ANSIBLE_DIR/inventory/offline/group_vars/all/secrets.yaml ]]; then
121127
echo "Writing $ANSIBLE_DIR/inventory/offline/group_vars/all/secrets.yaml"
@@ -127,7 +133,7 @@ minio_cargohold_secret_key: "$minio_cargohold_secret_key"
127133
EOT
128134
fi
129135

130-
PROM_AUTH_FILE="$VALUES_DIR/kube-prometheus-stack/secrets.yaml"
136+
PROM_AUTH_FILE="$VALUES_DIR/kube-prometheus-stack/prod-secrets.example.yaml"
131137
if [[ ! -f $PROM_AUTH_FILE ]]; then
132138
echo "Writing $PROM_AUTH_FILE"
133139
cat <<EOF > $PROM_AUTH_FILE
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Added: bin/helm-operations.sh to replace offline-helm to be more closer to our production instrcutions
2+
Changed: bin/offline-secrets.sh to support helm-operations.sh script and add support for coturn secret
3+
Changed: reduce replica count for sftd and coturn to support wiab-staging
4+
Changed: make using daemonset with nodePort for ingress-nginx-controller default for prod and make load-balancer an example

offline/cd.sh

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -122,9 +122,6 @@ ssh $SSH_OPTS "root@$adminhost" wget -q "https://s3-eu-west-1.amazonaws.com/publ
122122

123123
ssh $SSH_OPTS "root@$adminhost" tar xzf "$ARTIFACT.tgz"
124124

125-
# override for ingress-nginx-controller values for hetzner environment $TF_DIR/setup_nodes.yml
126-
scp $SSH_OPTS "$VALUES_DIR/ingress-nginx-controller/hetzner-ci.example.yaml" "root@$adminhost:./values/ingress-nginx-controller/prod-values.example.yaml"
127-
128125
scp $SSH_OPTS inventory.yml "root@$adminhost":./ansible/inventory/offline/inventory.yml
129126

130127
ssh $SSH_OPTS "root@$adminhost" cat ./ansible/inventory/offline/inventory.yml || true

offline/postgresql-cluster.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -890,7 +890,7 @@ Keep the Wire server password in sync with the Kubernetes secret. Choose one of
890890
- Orchestrated by the pipeline ([bin/offline-deploy.sh](../bin/offline-deploy.sh)):
891891
1. `postgresql-wire-setup.yml` ensures the K8s secret `wire-postgresql-external-secret` exists.
892892
2. [`bin/sync-k8s-secret-to-wire-secrets.sh`](../bin/sync-k8s-secret-to-wire-secrets.sh) writes the password into `values/wire-server/secrets.yaml`.
893-
3. `offline-helm.sh` deploys using the updated values file.
893+
3. `bin/helm-operations.sh` deploys using the updated values file.
894894

895895
#### Manual sync
896896
Use the generic sync script to copy the password from the K8s secret into your values file:

offline/wiab-staging.md

Lines changed: 24 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -138,66 +138,36 @@ Since the inventory is ready, please continue with the following steps:
138138
- **[Deploying Kubernetes and stateful services](docs_ubuntu_22.04.md#deploying-kubernetes-and-stateful-services)**
139139
- Run `d ./bin/offline-cluster.sh` to deploy Kubernetes and stateful services (Cassandra, PostgreSQL, Elasticsearch, Minio, RabbitMQ). This script deploys all infrastructure needed for Wire backend operations.
140140

141-
*Note: Ensure all Helm charts use the values and secrets files in their `values/` directories—do not run `helm install` without them, or it will fall back to defaults and the artifact-provided values won’t apply. Sample commands can be found at [offline-helm.sh](https://github.com/wireapp/wire-server-deploy/blob/master/bin/offline-helm.sh)*
142-
143-
### Wire Components Deployment
144-
145-
- **Deploying Helm charts**
146-
- **[Deploying stateless services and other dependencies](docs_ubuntu_22.04.md#deploying-stateless-dependencies)**
147-
- Deploy cassandra-external, elasticsearch-external, minio-external, rabbitmq-external and databases-ephemeral helm charts to set up connections to external data services and stateless database dependencies.
148-
149-
- **[Deploying Wire Server](docs_ubuntu_22.04.md#deploying-wire-server)**
150-
- Install the core Wire backend platform with `d helm install wire-server ./charts/wire-server`. Update `values/wire-server/values.yaml` with your domain and inspect `values/wire-server/secrets.yaml` for required secrets.
151-
152-
- **[Deploying webapp](docs_ubuntu_22.04.md#deploying-webapp)**
153-
- Deploy the Wire web application frontend. Set your domain name and configure it for user access to the Wire interface.
154-
155-
- **[Deploying team-settings](docs_ubuntu_22.04.md#deploying-team-settings)**
156-
- Install team management and settings services for enterprise features and team administration.
157-
158-
- **[Deploying account-pages](docs_ubuntu_22.04.md#deploying-account-pages)**
159-
- Deploy account management pages for user profile, password reset, and account-related functionalities.
160-
161-
- **[Deploying smallstep-accomp](docs_ubuntu_22.04.md#deploying-smallstep-accomp)**
162-
- Install the smallstep ACME companion for certificate management integration.
163-
164-
### Network & Security
165-
166-
- **[Enabling emails for wire](smtp.md)**
167-
- Configure SMTP for user onboarding via email. Deploy either a temporary SMTP service included in the bundle or integrate with your existing SMTP relay, and ensure proper network configuration for email delivery.
168-
169-
- **[Deploy ingress-nginx-controller](docs_ubuntu_22.04.md#deploy-ingress-nginx-controller)**
170-
- Install nginx ingress controller as the entry point for HTTP/HTTPS traffic routing to Wire services. This component is required for all traffic forwarding methods.
171-
172-
- **[Acquiring / Deploying SSL Certificates](docs_ubuntu_22.04.md#acquiring--deploying-ssl-certificates)**
173-
- Configure SSL/TLS certificates either by bringing your own or using cert-manager with Let's Encrypt. SSL certificates are required by the nginx-ingress-services helm chart for secure HTTPS connections.
174-
175-
> **Note (cert-manager & hairpin NAT):** When cert-manager performs HTTP-01 self-checks inside the cluster, traffic can hairpin (Pod → Node → host public IP → DNAT → Node → Ingress). If your nftables rules DNAT in PREROUTING without a matching SNAT on virbr0→virbr0, return packets may bypass the host and break conntrack, causing HTTP-01 timeouts. Also, strict rp_filter can drop asymmetric return packets. If cert-manager is deployed, verify whether hairpin handling is needed:
176-
>
177-
> - Enable hairpin SNAT for DNATed traffic (forces return traffic through the host):
178-
> ```bash
179-
> sudo nft insert rule ip nat POSTROUTING position 0 \
180-
> iifname "virbr0" oifname "virbr0" \
181-
> ct status dnat counter masquerade
182-
> ```
183-
> - Relax reverse-path filtering to loose mode to allow asymmetric flows:
184-
> ```bash
185-
> sudo sysctl -w net.ipv4.conf.all.rp_filter=2
186-
> sudo sysctl -w net.ipv4.conf.virbr0.rp_filter=2
187-
> ```
188-
> These settings help conntrack reverse DNAT correctly and avoid drops during cert-manager’s HTTP-01 challenges in NAT/bridge (virbr0) environments.
141+
### Helm Operations to install wire services and supporting helm charts
142+
143+
**Helm chart deployment (automated):** The script `bin/helm-operations.sh` will deploy the charts for you. It prepares `values.yaml`/`secrets.yaml`, customizes them for your domain/IPs, then runs Helm installs/upgrades in the correct order.
144+
145+
**User-provided inputs (set these before running):**
146+
- `TARGET_SYSTEM`: your domain (e.g., `wire.example.com` or `example.dev`).
147+
- `CERT_MASTER_EMAIL`: email used by cert-manager for ACME registration.
148+
- `HOST_IP`: public IP that matches your DNS A record (auto-detected if empty).
149+
150+
**Charts deployed by the script:**
151+
- External datastores and helpers: `cassandra-external`, `elasticsearch-external`, `minio-external`, `rabbitmq-external`, `databases-ephemeral`, `reaper`, `fake-aws`, `demo-smtp`.
152+
- Wire services: `wire-server`, `webapp`, `account-pages`, `team-settings`, `smallstep-accomp`.
153+
- Ingress and certificates: `ingress-nginx-controller`, `cert-manager`, `nginx-ingress-services`.
154+
- Calling services: `sftd`, `coturn`.
189155

190-
### Calling Services
156+
**Values and secrets generation:**
157+
- Creates `values.yaml` and `secrets.yaml` from `prod-values.example.yaml` and `prod-secrets.example.yaml` for each chart under `values/`.
158+
- Backs up any existing `values.yaml`/`secrets.yaml` before replacing them.
191159

192-
- **[Installing SFTD](docs_ubuntu_22.04.md#installing-sftd)**
193-
- Deploy the Selective Forwarding Unit (SFT) calling server for Wire's voice and video calling capabilities. Optionally enable cooperation with TURN servers and configure appropriate node annotations for external IPs.
160+
**Values configured by the script:**
161+
- Replaces `example.com` with `TARGET_SYSTEM` in Wire and webapp hostnames.
162+
- Enables cert-manager and sets `certmasterEmail` using `CERT_MASTER_EMAIL`.
163+
- Sets SFTD hosts and switches issuer to `letsencrypt-http01`.
164+
- Sets coturn listen/relay/external IPs using the calling node IP and `HOST_IP`.
194165

195-
- **[Installing Coturn](coturn.md)**
196-
- Deploy TURN/STUN servers for WebRTC connectivity, enabling peer-to-peer communication for calling services and ensuring connectivity through firewalls and NATs.
166+
*Note: The `bin/helm-operations.sh` script above deploys these charts; you do not need to run the Helm commands manually unless you want to customize or debug.*
197167

198168
## Network Traffic Configuration
199169

200-
### Bring traffic from Physical machine to Wire services in k8s cluster
170+
### Bring traffic from the physical machine to Wire services in the k8s cluster
201171

202172
If you used the Ansible playbook earlier, nftables firewall rules are pre-configured to forward traffic. If you set up VMs manually with your own hypervisor, you must manually configure network traffic flow using nftables.
203173

0 commit comments

Comments
 (0)