What is a simple build and deploy process using kubectl?

2/10/2020

I'm trying to understand what a good practice is for what I would assume is a pretty common scenario of building and deploying a kubernetes deployment using kubectl.

Scenario:

  • I want to build a project and deploy it to my cluster.
  • I’ve got a yaml file with my deployment (and related things), and some src code with a Dockerfile.
  • I want to avoid using :latest in the image tag as per Best Practice recommendation and instead use a unique tag for that image.
  • I have easy access to a unique identifier, either coming from CI or git sha that is available as an environment variable at time of building.

So that seems pretty simple:

docker build -t my-registry/my-app:${BUILD_NUMBER} .
docker push my-registry/my-app:${BUILD_NUMBER}
kubectl apply -f kube.yaml

Except that there is no native way to tell kubectl what image name to use.

I understand that kubectl does not support environment variable template substitution, but I've never seen just the usecase of image tags being mentioned explicitly.

I can use sed replacement but that seems to go against the spirit of 'no variable template support', and I barely understand what sed does when I write it, so I pitty the next developer who has to read my commands.

I feel like for such a basic scenario "I want to build and deploy to my cluster" there might be a simpler solution that doesn’t feel like it’s fighting kubectl.

Skaffold does a great job of assigning a tag and digest for each built image, but it would be nice to have a simple process to start with before bringing in more high level tooling.

  • Besides "Use Skaffold" or "Use Helm" what should I do to have a simple build + deploy process?
  • Is templating yaml files okay, either with sed, mo, or other replacement tools?
  • Are there any example projects that have a simple build and deploy pipeline using just kubectl and maybe kustomize?

kube.yaml (Note the lack of version on the image name)

apiVersion: apps/v1
kind: Deployment
metadata:
  namespace: example
  name: my-app
spec:
  minReadySeconds: 2
  strategy:
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0
  replicas: 1
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      name: my-app
      labels:
        app: my-app
    spec:
      containers:
        - name: my-app
          image: "my-registry/my-app"
          ports:
            - containerPort: 3000
          resources:
            limits:
              cpu: 300m
              memory: 600m
            requests:
              cpu: 50m
              memory: 100m
-- MaybeARabbit
kubectl
kubernetes

2 Answers

2/10/2020

for simple cases you can use kubectl run. for example:

kubectl run my-app --image=my-registry/my-app:${BUILD_NUMBER} --port=3000 --replicas=1 --env VAR=value --expose --limits 'cpu=300m,memory=600Mi'

in theory it's a deprecated command, but it's been deprecated for 2 years now and it's still there ;] anyway, if you feel unsafe about it, the message gives a hint how you can waste a day or 2 to make it in a non-deprecated way ;]

-- morgwai
Source: StackOverflow

2/10/2020

Is kubectl set image <deployment> <image> an option? It does what you are looking for, but it won't be reflected in your local copy of kube.yaml, so you would need to specify a dummy image for "my-registry/my-app" in kube.yaml to not confuse other developers that they have to change that value each time they want to re-deploy.

-- Frederik Bode
Source: StackOverflow