<p>I am not able to use <code>kubectl</code> command inside <code>gitlab-ci.yml</code> file.</p>
<p>I have already gone through the steps mentioned in the doc to add an existing cluster in the <a href="https://docs.gitlab.com/ee/user/project/clusters/add_remove_clusters.html#existing-kubernetes-cluster" rel="nofollow noreferrer">doc</a>.</p>
<p>Nowhere they have mentioned, How can I use <code>kubectl</code>.</p>
<p>I tried the below configuration.</p>
<pre><code>stages:
  - docker-build
  - deploy

docker-build-master:
  image: docker:latest
  stage: docker-build
  services:
    - docker:dind
  before_script:
    - docker login -u &quot;$CI_REGISTRY_USER&quot; -p &quot;$CI_REGISTRY_PASSWORD&quot; $CI_REGISTRY
  script:
    - docker build --pull -t &quot;$CI_REGISTRY_IMAGE:prod&quot; .
    - docker push &quot;$CI_REGISTRY_IMAGE:prod&quot;
  only:
    - master

deploy-prod:
  stage: deploy
  image: roffe/kubectl
  script:
    - kubectl apply -f scheduler-deployment.yaml
  only:
    - master
</code></pre>
<p>But I am getting below error,</p>
<pre><code>Executing &quot;step_script&quot; stage of the job script
00:01
Using docker image sha256:c8d24d490701efec4c8d544978b3e4ecc4855475a221b002a8f9e5e473398805 for roffe/kubectl with digest roffe/kubectl@sha256:ba13f8ffc55c83a7ca98a6e1337689fad8a5df418cb160fa1a741c80f42979bf ...
$ kubectl apply -f scheduler-deployment.yaml
error: unable to recognize &quot;scheduler-deployment.yaml&quot;: Get http://localhost:8080/api?timeout=32s: dial tcp [::1]:8080: connect: connection refused
Cleaning up file based variables
00:00
ERROR: Job failed: exit code 1
</code></pre>
<p>Clearly, it is not able to connect to the cluster, or maybe trying to connect to the cluster inside this <code>roffe/kubectl</code> image container.</p>
<p>When I remove the image, I get this error.</p>
<pre><code>/bin/bash: line 117: kubectl: command not found
</code></pre>
<p>I have gone through the whole doc I couldn't find a single example or reference that explains this part.</p>
<p>Please suggest how I can deploy to the existing k8s cluster.</p>
<p><em>Update</em></p>
<p>I went through this <a href="https://docs.gitlab.com/ee/user/project/clusters/index.html#deployment-variables" rel="nofollow noreferrer">doc</a> and I am using defined variables in my gitlab-ci.yml to update the context of the kubectl.</p>
<p>But still it doesn't work.</p>
<pre><code>deploy-prod:
  stage: deploy
  image: roffe/kubectl
  script:
    - echo $HOME
    - echo $KUBECONFIG
    - echo $KUBE_URL
    - mkdir -p $HOME/.kube
    - echo -n $KUBECONFIG | base64 -d &gt; $HOME/.kube/config
    - kubectl get pods
  only:
    - master
</code></pre>
<p>Error that I get,</p>
<pre><code>$ echo $HOME
/root
$ echo $KUBECONFIG
$ echo $KUBE_URL
$ mkdir -p $HOME/.kube
$ echo -n $KUBECONFIG | base64 -d &gt; $HOME/.kube/config
$ kubectl get pods
The connection to the server localhost:8080 was refused - did you specify the right host or port?
Cleaning up file based variables
00:01
ERROR: Job failed: exit code 1
</code></pre>

<p>To automate deployment with an existing cluster, You need to follow below steps:</p>
<p><em>1. Add you cluster to gitlab project.</em></p>
<p>Follow <a href="https://docs.gitlab.com/ee/user/project/clusters/add_remove_clusters.html#existing-kubernetes-cluster" rel="nofollow noreferrer">this doc</a>, and add your existing cluster</p>
<p><em>2. Build your project and push to docker or any registry</em></p>
<pre><code>stages:
  - docker-build
  - deploy

docker-build-master:
  image: docker:latest
  stage: docker-build
  services:
    - docker:dind
  before_script:
    - docker login -u &quot;$CI_REGISTRY_USER&quot; -p &quot;$CI_REGISTRY_PASSWORD&quot; $CI_REGISTRY
  script:
    - docker build --pull -t &quot;$CI_REGISTRY_IMAGE:prod&quot; .
    - docker push &quot;$CI_REGISTRY_IMAGE:prod&quot;
  only:
    - master
</code></pre>
<p><em>3. Apply your deployment.yml to cluster</em></p>
<p>To use <code>kubectl</code> inside <code>gitlab-ci.yml</code>, you need an image that has <code>kubectl</code>. The one that you have used will work.</p>
<p>But the <code>kubectl</code> inside the container has no idea about the context of cluster that you added earlier.</p>
<p>Now this is where gitlab's envrionment variable play their role.</p>
<blockquote>
<p>The default environment scope is *, which means all jobs, regardless of their environment, use that cluster. Each scope can be used only by a single cluster in a project, and a validation error occurs if otherwise. Also, jobs that don’t have an environment keyword set can’t access any cluster. <a href="https://docs.gitlab.com/ee/user/project/clusters/index.html#multiple-kubernetes-clusters" rel="nofollow noreferrer">see here</a></p>
</blockquote>
<p>So, when you added your cluster, it goes by default in scope <code>*</code> and will be passed to every job provided it uses some environment.</p>
<p>Also, When you create a cluster, gitlab create environment variables for that cluster by default, <a href="https://docs.gitlab.com/ee/user/project/clusters/index.html#deployment-variables" rel="nofollow noreferrer">see here</a>.</p>
<p>Important thing to notice is that it also adds an environment variable <code>KUBECONFIG</code>.</p>
<hr />
<p>In order to access your Kubernetes cluster, <code>kubectl</code> uses a configuration file. The default <code>kubectl</code> configuration file is located at  <code>~/.kube/config</code> and is referred to as the <code>kubeconfig</code> file.</p>
<p><code>kubeconfig</code> files organize information about clusters, users, namespaces, and authentication mechanisms. The <code>kubectl</code> command uses these files to find the information it needs to choose a cluster and communicate with it.</p>
<p>The loading order follows these rules:</p>
<ul>
<li><p>If the <code>--kubeconfig</code> flag is set, then only the given file is loaded. The flag may only be set once and no merging takes place.</p>
</li>
<li><p>If the <code>$KUBECONFIG</code> environment variable is set, then it is parsed as a list of filesystem paths according to the normal path delimiting rules for your system.</p>
</li>
<li><p>Otherwise, the <code>${HOME}/.kube/config</code> file is used and no merging takes place.</p>
</li>
</ul>
<p>So, <code>kubectl</code> command can use the variable <code>KUBECONFIG</code> to set the context <a href="https://kubernetes.io/docs/concepts/configuration/organize-cluster-access-kubeconfig/#merging-kubeconfig-files" rel="nofollow noreferrer">see here</a>.</p>
<p>So, your deployment job will be like below,</p>
<pre><code>deploy-prod:
  stage: deploy
  image: roffe/kubectl
  script:
    - kubectl get pods
    - kubectl get all
    - kubectl get namespaces
    - kubectl apply -f scheduler-deployment.yaml
  environment:
    name: production
    kubernetes:
      namespace: default
  only:
    - master
</code></pre>
<p><em>You can also set a  namespace  for the job with <code>environment.kubernetes.namespace</code></em></p>
