137

I've been using K8S ConfigMap and Secret to manage our properties. My design is pretty simple, that keeps properties files in a git repo and use build server such as Thoughtworks GO to automatically deploy them to be ConfigMaps or Secrets (on choice condition) to my k8s cluster.

Currently, I found it's not really efficient that I have to always delete the existing ConfigMap and Secret and create the new one to update as below:

  1. kubectl delete configmap foo

  2. kubectl create configmap foo --from-file foo.properties

Is there a nice and simple way to make above one step and more efficient than deleting current? potentially what I'm doing now may compromise the container that uses these configmaps if it tries to mount while the old configmap is deleted and the new one hasn't been created.

David Maze
  • 130,717
  • 29
  • 175
  • 215
James Jiang
  • 2,073
  • 6
  • 19
  • 25
  • I just created a project to map configmap to environment values automatically, it can be useful for someone. https://github.com/Acanguven/kubernetes-configmap-update – Ahmet Can Güven Mar 22 '18 at 22:35

6 Answers6

228

You can get YAML from the kubectl create configmap command and pipe it to kubectl apply, like this:

kubectl create configmap foo --from-file foo.properties -o yaml --dry-run=client | kubectl apply -f -
captncraig
  • 22,118
  • 17
  • 108
  • 151
Jordan Liggitt
  • 16,933
  • 2
  • 56
  • 44
  • 5
    Pipe the command is the way to go, wasn't thinking of the --dry-run which appears to be the key part of the command! – James Jiang Jul 06 '16 at 04:50
  • 5
    For what its worth, this same pattern can work for Secrets in addition to ConfigMaps example shown here. – rwehner Jul 06 '16 at 15:34
  • 4
    trying this with kubernetes 1.10 but i keep getting the error `error: error validating "STDIN": error validating data: [apiVersion not set, kind not set]; if you choose to ignore these errors, turn validation off with --validate=false` – yee379 Apr 14 '18 at 09:26
  • 2
    that's a bug in 1.10 resolved in 1.10.1 - see https://github.com/kubernetes/kubernetes/issues/61780 and https://github.com/kubernetes/kubernetes/pull/61808 – Jordan Liggitt Apr 14 '18 at 14:31
  • For secrets you can simply use `kubectl replace -f secret.yaml` I think. – Jesse Glick Sep 10 '18 at 15:07
  • 8
    Great answer. using `kubectl apply` instead of `kubectl replace`, will work both for new and existing configmap – nahsh Nov 24 '19 at 13:08
  • @nahsh, what do you think about this? What is better? https://stackoverflow.com/questions/38216278/update-k8s-configmap-or-secret-without-deleting-the-existing-one#comment109131681_42138855 – Alex MM May 09 '20 at 12:53
  • The comment from nahsh and the answer from @karthik-c are much more useful and in all honesty, deserves to be the marked answer. – Rads Mar 09 '21 at 10:01
  • 1
    Note that `--dry-run` is deprecated and should in this case be replaced with `--dry-run=client`. `kubectl create configmap -h` will show why, it will still create the configmap, but only client-side, not sending it to the server. That is done in the next step. – Andreas L Mar 26 '21 at 11:32
  • 1
    With `v.17.17`, `kubectl replace -f -` updated an existing configmap but did not create the configmap if it did not already exist. Both use cases worked after I changed the replace command to `kubectl replace --force -f -`. – user100464 Apr 16 '21 at 16:20
46

For future reference, kubectl replace is now a very handy way to achieve this

kubectl replace -f some_spec.yaml Let you update a complete configMap (or other objects)

See doc and examples directly here

Copy/pasted from the help:

# Replace a pod using the data in pod.json.
kubectl replace -f ./pod.json

# Replace a pod based on the JSON passed into stdin.
cat pod.json | kubectl replace -f -

# Update a single-container pod's image version (tag) to v4
kubectl get pod mypod -o yaml | sed 's/\(image: myimage\):.*$/\1:v4/' | kubectl replace -f -

# Force replace, delete and then re-create the resource
kubectl replace --force -f ./pod.json
foka
  • 804
  • 9
  • 27
  • 3
    This missed the `--from-file` requirement. Configmaps can be created from an arbitrary file, not just the yaml. – Dave Hillier Jul 05 '18 at 07:17
  • @sébastien-portebois thanks! I didn't know the `--force` option, what would allow us to use the approach ` | kubectl replace --force -f -` command even the 1st time, when the ConfigMap does not exist yet. But I am not sure if it is secure to delete the ConfigMap as Pods may break during its lack due to not finding it. Maybe it is better the approach ` | kubectl apply -f -`? This point was kind of introduced by @karthic-c, what do you think? Also @jordan-liggitt what do you think? – Alex MM May 09 '20 at 12:50
  • What’s the difference to ‘apply’? – Marc Feb 24 '22 at 07:33
40

For small changes in configMap, use edit

kubectl edit configmap <cfg-name>

This will open configMap in vi editor. Make the changes and save it.

deepdive
  • 9,720
  • 3
  • 30
  • 38
  • 4
    Cool. However, as OP mentioned, this is about how to achieve the goal with automated processes, eg. with the ThoughtWorks Go as building server in my scenario. – James Jiang Jan 09 '19 at 02:42
33

kubectl replace fails if a configmap does not already exist:

$ kubectl create configmap foo --from-file foo.properties -o yaml --dry-run=client | kubectl replace -f -

Error from server (NotFound): error when replacing "STDIN": configmaps "falco-config" not found

Best solution is to use kubectl apply which would create configmap if not present else update configmap if it is present:

$ kubectl create configmap foo --from-file foo.properties -o yaml --dry-run=client | kubectl apply -f -

configmap/falco-config configured

Jordan Liggitt
  • 16,933
  • 2
  • 56
  • 44
Karthik C
  • 401
  • 5
  • 7
  • 7
    I think you mean "`kubectl replace` fails if a configmap _does not_ already exist". – David Dooling Apr 30 '20 at 18:48
  • 3
    This answer needs to get bumped up or get visibility somehow, as a lot of people who end up on this page are looking forward to an idempotent solution with config create... – Rads Mar 09 '21 at 09:59
  • Consider adding `--save-config` to kubectl create command. – Stevo Slavić Jan 20 '22 at 14:06
  • There is a ‘—force’ flag which avoids the error and creates it. I also think apply does an overlay and might not delete any keys you removed. – Marc Feb 24 '22 at 07:35
9

Take a copy of the existing configmap:

kubectl get configmap foo -o yaml > foo.yaml

And then do the modifications and use apply command, this should work.

kubectl apply -f foo.yaml

Note: Incase if you see any of the following issue, then include latest "resourceVersion" from the existing config map and try again.

" Operation cannot be fulfilled on configmaps "foo": the object has been modified; please apply your changes to the latest version and try again"

Vallabha Vamaravelli
  • 1,153
  • 1
  • 9
  • 15
2

You may think about using GitOps to achieve it. In my case I use ArgoCD as the gitops tool and it detects K8S yaml files in Github then apply the changes automatically.

Owen Sun
  • 47
  • 5