<p>I currently have a GitHub repository that contains my application code and a Kubernetes deployment configuration file (called <code>deployment.yml</code>). I.e., my repository has the following structure:</p>
<pre><code>repository
  +- ...application code...
  +- Dockerfile
  \- deployment.yml
</code></pre>
<p>When a change is pushed to this GitHub repository, a series of GitHub Actions are executed that containerize my application into a Docker image and publish that image to Docker Hub.</p>
<p>On a development machine, I have a Kubernetes cluster running. I pull the <code>deployment.yml</code> file from the repository and either apply that configuration using <code>kubectl apply -f deployment.yml</code> or perform a rolling-update using <code>kubectl rollout restart deployment/&lt;name&gt;</code>.</p>
<p>My <code>deployment.yml</code> is configured as follows:</p>
<pre><code>apiVersion: apps/v1
kind: Deployment
metadata:
  ...
spec:
  replicas: 1
  ...
  template:
    ...
    spec:
      containers:
      - name: &lt;name&gt;
        image: foo/bar:v1.0.0
        imagePullPolicy: IfNotPresent
        ports:
          - containerPort: &lt;port&gt;
      imagePullSecrets:
      - name: &lt;creds-id&gt;
</code></pre>
<p>The version of the image (i.e., <code>v1.0.0</code> in <code>foo/bar:v1.0.0</code>) originates from the tags I use in Git. I.e., if I tag a commit as <code>v1.0.0</code>, a new build is run for that tag and a new Docker image is published to Docker Hub with the tag <code>v1.0.0</code>.</p>
<p>My problem is that I am storing my Kubernetes configuration (<code>deployment.yml</code>) in the same repository that is being tagged. This means that I am tagging a commit (i.e., <code>v2.0.0</code>) that contains an image of <code>foo/bar:v1.0.0</code> in the <code>deployment.yml</code>. I.e., I make changes to my code and then decide once those changes are sufficient, that a specific commit will be tagged. Since I want the cluster on my development machine to use the latest, approved (i.e., tagged) code, I then go an update the <code>deployment.yml</code> and commit, but that new commit is after the tagged commit.</p>
<p>To resolve this, I would have to change the <code>deployment.yml</code> file for the commit I know will be tagged. I.e., knowing that the next commit I make will be tagged as <code>v2.0.0</code>, I will have to change the <code>deployment.yml</code> to use the image <code>foo/bar:v2.0.0</code> and add that change to the commit (i.e., the one to be tagged). In that case, the commit tagged as <code>v2.0.0</code> will have an image of <code>foo/bar:v2.0.0</code> in its <code>deployment.yml</code>.</p>
<p>Is there a technique or best practice (such as templating or another practice) that can solve this issue?</p>
<p>Thank you.</p>

<p><strong>Helm</strong> templating is also a good option however if your project is basic and won't be much requirement there use this basic method keeping the <strong>deployment.yaml</strong> in repo simple way.</p>
<p>Ideally, you can keep your <strong>deployment</strong> file dynamic as much as possible rather than fix values to the add-in.</p>
<pre><code>apiVersion: apps/v1beta2
kind: Deployment
metadata:
  name: test-image
  labels:
    app: test-image
spec:
  selector:
    matchLabels:
      app: test-image
      tier: frontend
  strategy:
    type: RollingUpdate
  template:
    metadata:
      labels:
        app: test-image
        tier: frontend
    spec:
      containers:
      - image: TEST_IMAGE_NAME
        name: test-image
        ports:
        - containerPort: 8080
          name: http
        - containerPort: 443
          name: https
</code></pre>
<p>and in the <strong>YAML</strong> <strong>CI</strong> config we change the <strong>IMAGE URL</strong> in deployment.yaml file as per need.</p>
<p><code>Google could build</code> CI file example, however you can write or update the logic in your <strong>YAML</strong> CI</p>
<pre><code>steps:
- id: 'set test core image in yamls'
  name: 'ubuntu'
  args: ['bash','-c','sed -i &quot;s,TEST_IMAGE_NAME,gcr.io/$PROJECT_ID/$REPO_NAME/$BRANCH_NAME:$SHORT_SHA,&quot; deployment.yaml']
</code></pre>
<p>In your process, the <strong>YAML</strong> file and run time replace the string with <strong>URL</strong> you want to add.</p>
<p><strong>Git</strong> will give you necessary variables like <strong>COMMIT HASH</strong> or <strong>TAGGED VERSION</strong>.</p>
<p>Example <strong>CI</strong> file <strong>YAML</strong> file,</p>
<pre><code>steps:
- id: 'build test core image'
  name: 'gcr.io/cloud-builders/docker'
  args: ['build', '-t', 'gcr.io/$PROJECT_ID/$REPO_NAME/$BRANCH_NAME:$SHORT_SHA', '.']
- id: 'push test image'
  name: 'gcr.io/cloud-builders/docker'
  args: ['push', 'gcr.io/$PROJECT_ID/$REPO_NAME/$BRANCH_NAME:$SHORT_SHA']
- id: 'set test core image in yamls'
  name: 'ubuntu'
  args: ['bash','-c','sed -i &quot;s,TEST_IMAGE_NAME,gcr.io/$PROJECT_ID/$REPO_NAME/$BRANCH_NAME:$SHORT_SHA,&quot; deployment.yaml']
- name: 'gcr.io/cloud-builders/kubectl'
  args: ['apply', '-f', 'deployment.yaml']
</code></pre>
<p>inside your <code>deployment.yaml</code> there will be one string <code>TEST_IMAGE_NAME</code> which will get replaced during the <code>CI</code> operation</p>
<p>using simple ubuntu command <strong>sed</strong> : <code>sed -i &quot;s,TEST_IMAGE_NAME,gcr.io/$PROJECT_ID/$REPO_NAME/$BRANCH_NAME:$SHORT_SHA,&quot; deployment.yaml</code></p>
<p>variables like <code>$SHORT_SHA</code> will get auto injected or added by <strong>Github</strong> so now on your <strong>CI server</strong> you have one <code>deployment.yaml</code> with <code>Image-URL</code> that you have pushed to docker hub.</p>
<p>We have replaced our <code>TEST_IMAGE_NAME</code> string in <code>deployment.yaml</code> dynamically during CI.</p>
<p>Now you can apply this <code>deployment.yaml</code> from CI server, &amp; it will update or push the deployment to <strong>K8s</strong> cluster wherever it's running.</p>
<p><strong>Note</strong> :</p>
<p>if you want to store the config in repo also, you can commit back file from CI server repo, you have to store <code>3</code> deployment file, dev-<code>deploymentl.yaml</code>, <code>stag-deployment.yaml</code> if any changes in any branch you can commit that file from CI server to repo again and your YAML config will be saved in <strong>repo</strong> also.</p>
