Configure service DNS / ingress¶
TL;DR — Adds a Kubernetes ingress rule for a backend microservice in
ops-k8s-infrafor dev, rc, and/or sandbox. Production DNS changes require a DevOps ticket — this workflow explicitly skips prod.
Overview¶
Backend microservices are exposed via ingress rules in securitize_dev/ops-k8s-infra. Each environment × service-type combination maps to a specific YAML file. This workflow:
- Collects service name, type, port, and target environments from the developer.
- Loads the file path table and host patterns from the wiki (SSOT).
- Checks whether the rule already exists.
- Appends the rule for environments where it is missing.
- Creates a PR in
ops-k8s-infra.
File paths, host patterns, and service type descriptions live exclusively in wiki/repositories/ops-repos.md → Ingress and DNS configuration. Load that wiki page before Step 2 — do not rely on memory for file paths.
Production DNS is not in scope
ops-k8s-infra covers dev, rc, and sandbox only. Production DNS / ingress changes require a DevOps ticket via the Service Desk. Do not attempt to add prod rules — stop and redirect the developer.
Inputs¶
Collect all of these from the developer before cloning anything:
| Input | Description | Values |
|---|---|---|
service_name |
K8s service name — must match the deployment name in ops-scripts |
e.g. my-svc |
service_type |
How the service is exposed | internal, public, or gateway |
port |
Service port | default 8080 |
environments |
Which environments to add the rule to | any subset of dev, rc, sandbox |
If the developer is unsure which service_type to pick, point them to the wiki's "Service types and browser URLs" table — it lists who can reach each type and the resulting browser URL.
For gateway, the YAML host differs from the browser URL — always use the host string the wiki resolves for the service type (see the wiki's "Why gateway browser URL and YAML host don't match" tip for the full explanation).
Steps¶
Shell-session note — If you run each bash command in a separate subshell,
REPO_DIRdoes not persist. Re-derive it in any step after Step 1 as:
1. Clone ops-k8s-infra¶
REPO_DIR="$HOME/.securitize/tmp/ops-k8s-infra-$(date +%Y%m%d%H%M%S)"
mkdir -p "$HOME/.securitize/tmp"
git clone --depth 1 git@bitbucket.org:securitize_dev/ops-k8s-infra.git "$REPO_DIR"
# Confirm mainline is master — every ops-* repo branches from master, not dev
git -C "$REPO_DIR" rev-parse --abbrev-ref HEAD # must print: master
If the clone fails, ask the developer to verify SSH access to securitize_dev, then stop. If the confirm command does not print master, stop — ops-k8s-infra uses master as its mainline; do not proceed on any other branch.
2. Load the wiki and check whether the rule already exists¶
Before doing anything in the repo, load the ingress reference from the wiki — it is the SSOT for file paths, host patterns, and the current vs at capacity model:
Read the "Ingress and DNS configuration" section. From it, extract, for each requested environment × service_type:
- The read set — every file listed in the wiki's "Read target — full file set per env × service_type" table.
- The current file — the single write target from the wiki's "Write target — the current file per env × type" table.
- The host string format for the service type.
Build the grep from the wiki's read set — never a single file
Including every file from the read set in one grep is mandatory. The wiki explains why (the at capacity model and the ALB rule limit). A single-file grep yields false MISSING and duplicated rules on apply.
For each requested environment, run one grep across the full read set:
HOST="<computed_host>"
# Replace placeholders with EVERY file from the wiki's read set for this env × service_type:
grep -l "host: $HOST" \
"$REPO_DIR/<file_1>" \
"$REPO_DIR/<file_2>" \
... \
2>/dev/null
- Any printed file → status
EXISTS(note which file matched). - No output → status
MISSING.
Build a summary table — include the matched file (or (no match)) so the check is auditable:
| Env | Read set (from wiki) | Host | Grep match | Status |
|---|---|---|---|---|
<env> |
<file_1> (current), <file_2> (at capacity), ... |
<host> |
(no match) |
MISSING |
<env> |
<file_1> (current), <file_2> (at capacity), ... |
<host> |
<matched_file> |
EXISTS — skip |
Show the table to the developer before writing anything. If all environments are EXISTS, stop — there is nothing to add. Otherwise ask for confirmation before proceeding to Step 3.
3. Append missing rules¶
For each environment with status MISSING, append the rule to the current file for that env × service_type (from the wiki's "Write target" table). Never write to a file marked at capacity — see the wiki for the reason.
Detect the indentation from the last existing - host: entry and append at the end of the file:
YAML_FILE="$REPO_DIR/<current_file>"
HOST="<computed_host>"
SERVICE_NAME="<service_name>"
PORT=<port>
# Detect indentation from existing entries (fallback: 4 spaces)
INDENT=$(grep "- host:" "$YAML_FILE" | tail -1 | sed 's/- host:.*//')
[ -z "$INDENT" ] && INDENT=" "
I0="${INDENT}"
I2="${INDENT} "
I4="${INDENT} "
I6="${INDENT} "
I8="${INDENT} "
I10="${INDENT} "
I12="${INDENT} "
I14="${INDENT} "
# Ensure file ends with a newline before appending
[ -n "$(tail -c 1 "$YAML_FILE")" ] && echo "" >> "$YAML_FILE"
cat >> "$YAML_FILE" <<EOF
${I0}- host: ${HOST}
${I2}http:
${I4}paths:
${I6}- path: /*
${I8}pathType: ImplementationSpecific
${I8}backend:
${I10}service:
${I12}name: ${SERVICE_NAME}
${I12}port:
${I14}number: ${PORT}
EOF
Repeat for each MISSING environment.
4. Show the diff and confirm¶
Show the full diff to the developer. If they want adjustments, return to Step 3. Do not proceed until they confirm.
5. Create branch (from master) and push¶
Branch from master, not dev
ops-k8s-infra — like every ops-* repo — uses master as its mainline. Do not substitute dev even if a generic PR procedure suggests it as a default. This workflow's branching base is non-negotiable: the PR destination is master (Step 6) and the source branch must also be cut from master.
BRANCH="feature/dns-${SERVICE_NAME}-$(date +%Y%m%d%H%M%S)"
cd "$REPO_DIR"
git checkout -b "$BRANCH" master # explicit base = master — do not change to dev
git add .
git commit -m "chore: add ingress rule for ${SERVICE_NAME} (${SERVICE_TYPE})"
git push origin "$BRANCH"
6. Open the Pull Request¶
Target: securitize_dev/ops-k8s-infra, source = branch from Step 5, destination = master.
Preferred — open the PR through any Bitbucket-capable MCP you have available. Tool names and parameter shapes vary by server (mcp__bitbucket__*, mcp__atlassian__*, custom servers, etc.); scan your tool list for tools that act on Bitbucket pull requests. Whatever the surface, perform two operations:
- Resolve the repo's effective default reviewers for
workspace=securitize_dev,repo=ops-k8s-infra. Keep the returned user identifiers (UUIDs / account IDs / whatever the server uses). - Create the pull request with:
source={BRANCH}(from Step 5)destination=mastertitle=chore: add ingress rule for {service_name} ({service_type})description= summary table from Step 2reviewers= the identifiers from (1)
Fallback — no Bitbucket MCP available. Show the developer the manual URL and stop:
https://bitbucket.org/securitize_dev/ops-k8s-infra/pull-requests/new?source={BRANCH}&dest=master
In either path, show the final PR link to the developer.
7. Clean up¶
Verification¶
- PR is open on
securitize_dev/ops-k8s-infraagainstmaster. - The diff contains exactly one
- host:block per requested environment, in the correct YAML files. - No rule was duplicated — each host appeared as
MISSINGbefore being appended.
Rollback¶
This workflow writes nothing outside the temporary clone until the branch is pushed.
- Before push (Steps 1-5):
rm -rf "$REPO_DIR"discards everything. - After push, before merge: close the PR in Bitbucket; delete the remote branch.
- After merge: open a revert PR in
ops-k8s-infraremoving the- host:block(s) from the affected YAML files.
See also¶
- wiki/repositories/ops-repos.md —
ops-k8s-infrastructure, service types, and the canonical file path table.