<p>I came across Skaffold, trying to streamline local Docker image development. We basically want to be able to quickly iterate on an image and deploy it using an existing stable helm chart version.</p>

<p>In the documentation it says:</p>

<p><a href="https://github.com/GoogleContainerTools/skaffold#installation" rel="noreferrer">https://github.com/GoogleContainerTools/skaffold#installation</a></p>

<blockquote>
  <ol start="5">
  <li>Docker image registry.
  Your docker client should be configured to push to an external docker
  image repository. If you're using a minikube or Docker for Desktop
  cluster, you can skip this requirement.</li>
  </ol>
</blockquote>

<p>However, when I'm trying to run the example <code>examples/helm-deployment</code> it actually tries to connect to a registry:</p>

<pre><code>$ skaffold dev
...
The push refers to repository [docker.io/library/skaffold-helm]
b3fb485368bf: Preparing
6f67560e4591: Preparing
d626a8ad97a1: Preparing
WARN[0012] run: build: build step: running push: denied: requested access to the resource is denied
</code></pre>

<p>Do I always need a registry, even using Minikube and Skaffold?</p>

<p>With skaffold, you don't need any registry if you want to deploy to minikube. By default, it <a href="https://github.com/GoogleContainerTools/skaffold/blob/a0c641b4d626b604e34e765d851a05207b253639/examples/annotated-skaffold.yaml#L60" rel="noreferrer">seamlessly puts</a> the image to minikube without any external registry involved.</p>

<p>Consider the following <code>deployment.yaml</code> file:</p>

<pre><code>apiVersion: apps/v1beta1
kind: Deployment
metadata:
  name: petstore-frontend
  labels:
    app: petstore
    tier: frontend
spec:
  replicas: 1
  selector:
    matchLabels:
      app: petstore
      tier: frontend
  template:
    metadata:
      labels:
        app: foo
        tier: frontend
    spec:
      containers:
        - name: frontend
          image: petstore/frontend
          imagePullPolicy: Always
          ports:
            - containerPort: 80
</code></pre>

<p>Note that <code>image</code> field does not contain any tag, because skaffold will inject one for you.</p>

<p>The minimal <code>skaffold.yaml</code> file would look like this:</p>

<pre><code>apiVersion: skaffold/v1alpha2
kind: Config
profiles:
  - name: minikube
    build:
      artifacts:
        - imageName: petstore/frontend
    deploy:
        manifests:
          - deployment.yaml
</code></pre>

<p>Here, <code>imageName</code> should match the <code>image</code> field value from <code>deployment.yaml</code> file.</p>

<p>Now you can just run <code>skaffold run -p minikube</code> and it will build your image, put it to minikube and apply the deployment.</p>

<p><strong>However</strong>, when deploying via Helm charts, there are the small but important things you also need to specify.</p>

<p>Consider the following <code>deployment.yaml</code> template (I've omited some fields for brevity):</p>

<pre><code>apiVersion: apps/v1beta1
kind: Deployment
metadata:
  name: {{ template "petstore-frontend.fullname" . }}
  labels:
    # &lt;labels&gt;
spec:
  replicas: 1
  selector:
    matchLabels:
      # &lt;labels&gt;
  template:
    metadata:
      labels:
        # &lt;labels&gt;
    spec:
      containers:
        - name: {{ template "petstore-frontend.name" . }}
          image: {{ .Values.image.repository }}{{ if .Values.image.tag }}:{{ .Values.image.tag }}{{ end }}
          imagePullPolicy: Always
          ports:
            - containerPort: 80
</code></pre>

<p>It is important to have a possibility to specify image without any tag, so skaffold can inject it for you.</p>

<p>Then a <code>skaffold.yaml</code> file would look like this:</p>

<pre><code>apiVersion: skaffold/v1alpha2
kind: Config
profiles:
  - name: minikube
    build:
      artifacts:
        - imageName: petstore/frontend
    deploy:
      helm:
        releases:
          - name: petstore-frontend
            chartPath: charts/petstore-frontend
            values:
              "image.repository": petstore/frontend
            setValues:
              "image.tag": ""
</code></pre>

<p>Here, <code>image.repository</code> should be exactly the same as <code>imageName</code> in <code>artifacts</code> section, and also <code>image.tag</code> is set an empty string to, as it was said above, allow skaffold to inject it.</p>

<p>In conclusion, it is worth to mention that skaffold is still in alpha, so the API may change, and maybe that "tricks" won't be needed anymore. Still, skaffold already provides much convenience for rapid application development and deployment.</p>

<p>I hope this helps.</p>
