<p>We have <a href="https://github.com/jonashackt/tekton-argocd-eks" rel="nofollow noreferrer">a EKS cluster running with Traefik deployed in CRD style (full setup on GitHub</a>) and wan't to deploy our app <a href="https://gitlab.com/jonashackt/microservice-api-spring-boot" rel="nofollow noreferrer">https://gitlab.com/jonashackt/microservice-api-spring-boot</a> with the Kubernetes objects Deployment, Service and IngressRoute (see <a href="https://gitlab.com/jonashackt/microservice-api-spring-boot-config" rel="nofollow noreferrer">configuration repository here</a>). The manifests look like this:</p>
<p><code>deployment.yml</code>:</p>
<pre><code>apiVersion: apps/v1
kind: Deployment
metadata:
  name: microservice-api-spring-boot
spec:
  replicas: 3
  revisionHistoryLimit: 3
  selector:
    matchLabels:
      app: microservice-api-spring-boot
      branch: main
  template:
    metadata:
      labels:
        app: microservice-api-spring-boot
        branch: main
    spec:
      containers:
        - image: registry.gitlab.com/jonashackt/microservice-api-spring-boot:c25a74c8f919a72e3f00928917dc4ab2944ab061
          name: microservice-api-spring-boot
          ports:
            - containerPort: 8098
      imagePullSecrets:
        - name: gitlab-container-registry
</code></pre>
<p><code>service.yml</code>:</p>
<pre><code>apiVersion: v1
kind: Service
metadata:
  name: microservice-api-spring-boot
spec:
  ports:
    - port: 80
      targetPort: 8098
  selector:
    app: microservice-api-spring-boot
    branch: main
</code></pre>
<p><code>traefik-ingress-route.yml</code>:</p>
<pre><code>apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: microservice-api-spring-boot-ingressroute
  namespace: default
spec:
  entryPoints:
    - web
  routes:
    - match: Host(`microservice-api-spring-boot-BRANCHNAME.tekton-argocd.de`)
      kind: Rule
      services:
        - name: microservice-api-spring-boot
          port: 80
</code></pre>
<p>We already use <a href="https://kustomize.io/" rel="nofollow noreferrer">Kustomize</a> and especially the <code>kustomize</code> CLI (on a Mac or in GitHub Actions install with <code>brew install kustomize</code>) with the following folder structure:</p>
<pre><code>├── deployment.yml
├── kustomization.yaml
├── service.yml
└── traefik-ingress-route.yml
</code></pre>
<p>Our <code>kustomization.yaml</code> looks like this:</p>
<pre><code>apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
- deployment.yml
- service.yml
- traefik-ingress-route.yml

images:
- name: registry.gitlab.com/jonashackt/microservice-api-spring-boot
  newTag: foobar

commonLabels:
  branch: foobar

nameSuffix: foobar
</code></pre>
<p>Now changing the <code>metadata.name</code> dynamically to add a suffix to the Deployment's, Service's and IngressRoute's <code>.metadata.name</code> from within our GitHub Actions workflow is easy with <code>kustomize</code> CLI (because we want the suffix to use a prefixed <code>-</code>, we need to use the <code>-- -barfoo</code> syntax here):</p>
<pre><code>kustomize edit set namesuffix -- -barfoo
</code></pre>
<p>Check the result with</p>
<pre><code>kustomize build .
</code></pre>
<p>Also changing the <code>.spec.selector.matchLabels.branch</code>, <code>.spec.template.metadata.labels.branch</code> and <code>.spec.selector.branch</code> in the Deployment and Service is no problem:</p>
<pre><code>kustomize edit set label branch:barfoo
</code></pre>
<p>Changing the <code>.spec.template.spec.containers[0].image</code> of our Deployment works with:</p>
<pre><code>kustomize edit set image registry.gitlab.com/jonashackt/microservice-api-spring-boot:barfoo
</code></pre>
<p><strong>But looking into our <code>IngressRoute</code> it seems that <code>.spec.routes[0].services[0].name</code> and <code>.spec.routes[0].match = Host()</code> can't be changed with Kustomize out of the box?! So how can we change both fields without the need for a replacement tooling like yq or even <code>sed</code>/ <code>envsubst</code>?</strong></p>

jonashackt
<h2><strong>1. Change the <code>IngressRoute</code>s <code>.spec.routes[0].services[0].name</code> with Kustomize</strong></h2>
<p>Changing the <code>IngressRoute</code>s <code>.spec.routes[0].services[0].name</code> is possible with Kustomize using <a href="https://github.com/kubernetes-sigs/kustomize/blob/master/examples/transformerconfigs/README.md#name-reference-transformer" rel="nofollow noreferrer">a <code>NameReference</code> transformer (see docs here)</a> - luckily I found inspiration <a href="https://github.com/kubernetes-sigs/kustomize/issues/2673" rel="nofollow noreferrer">in this issue</a>. Therefore we need to include the <code>configurations</code> keyword in our <code>kustomize.yaml</code>:</p>
<pre><code>nameSuffix: foobar
configurations:
  # Tie target Service metadata.name to IngressRoute's spec.routes.services.name
  # Once Service name is changed, the IngressRoute referrerd service name will be changed as well.
  - nameReference.yml
</code></pre>
<p>We also need to add file called <code>nameReference.yml</code>:</p>
<pre><code>nameReference:
  - kind: Service
    fieldSpecs:
      - kind: IngressRoute
        path: spec/routes/services/name
</code></pre>
<p>As you can see we tie the Service's <code>name</code> to the IngressRoutes <code>spec/routes/services/name</code>. Now running</p>
<pre><code>kustomize edit set namesuffix barfoo
</code></pre>
<p>will not only change the <code>metadata.name</code> tags of the Deployment, Service and IngressRoute - but also the <code>.spec.routes[0].services[0].name</code> of the IngressRoute, since it is now linked to the <code>metadata.name</code> of the Service. Note that this only, if both the referrer and the target's have a <code>name</code> tag.</p>
<h2><strong>2. Change a part of the IngressRoutes <code>.spec.routes[0].match = Host()</code></strong></h2>
<p>The second part of the question ask how to change a part of the IngressRoutes <code>.spec.routes[0].match = Host()</code>. There's <a href="https://github.com/kubernetes-sigs/kustomize/issues/4012" rel="nofollow noreferrer">an open issue in the Kustomize GitHub project</a>. Right now Kustomize doesn't support this use case - only writing a custom generator plugin for Kustomize. As this might not be a preferred option, there's another way inspired by <a href="https://traefik.io/blog/deploy-traefik-proxy-using-flux-and-gitops/" rel="nofollow noreferrer">this blog post</a>. As we can create yaml files inline in our console using the syntax <code>cat &gt; ./myyamlfile.yml &lt;&lt;EOF ... EOF</code> we could also use the inline variable substitution.</p>
<p>So first define the branch name as variable:</p>
<pre><code>RULE_HOST_BRANCHNAME=foobar
</code></pre>
<p>And then use the described syntax to create a <code>ingressroute-patch.yml</code> file inline:</p>
<pre><code>cat &gt; ./ingressroute-patch.yml &lt;&lt;EOF
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: microservice-api-spring-boot-ingressroute
  namespace: default
spec:
  entryPoints:
    - web
  routes:
    - match: Host(\`microservice-api-spring-boot-$RULE_HOST_BRANCHNAME.tekton-argocd.de\`)
      kind: Rule
      services:
        - name: microservice-api-spring-boot
          port: 80

EOF
</code></pre>
<p>The last step is to use the <code>ingressroute-patch.yml</code> file as <code>patchesStrategicMerge</code> inside our <code>kustomization.yaml</code> like this:</p>
<pre><code>patchesStrategicMerge:
  - ingressroute-patch.yml
</code></pre>
<p>Now running <code>kustomize build .</code> should output the correct Deployment, Service and IngressRoute for our setup:</p>
<pre><code>apiVersion: v1
kind: Service
metadata:
  labels:
    branch: barfoo
  name: microservice-api-spring-boot-barfoo
spec:
  ports:
  - port: 80
    targetPort: 8098
  selector:
    app: microservice-api-spring-boot
    branch: barfoo
---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    branch: barfoo
  name: microservice-api-spring-boot-barfoo
spec:
  replicas: 3
  revisionHistoryLimit: 3
  selector:
    matchLabels:
      app: microservice-api-spring-boot
      branch: barfoo
  template:
    metadata:
      labels:
        app: microservice-api-spring-boot
        branch: barfoo
    spec:
      containers:
      - image: registry.gitlab.com/jonashackt/microservice-api-spring-boot:barfoo
        name: microservice-api-spring-boot
        ports:
        - containerPort: 8098
      imagePullSecrets:
      - name: gitlab-container-registry
---
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  labels:
    branch: barfoo
  name: microservice-api-spring-boot-ingressroute-barfoo
  namespace: default
spec:
  entryPoints:
  - web
  routes:
  - kind: Rule
    match: Host(`microservice-api-spring-boot-barfoo.tekton-argocd.de`)
    services:
    - name: microservice-api-spring-boot-barfoo
      port: 80
</code></pre>
