I'm daily user of kubectl, but not expert of linux. Recently I need edit some service type after deployment, so searched and used kubectl replace and it worked well.
cat yaml | kubectl replace -f -
service/tracs-pool-1sv replaced
But I don't understand why add a short dash -
at the last. The doc only says:
Replace a pod based on the JSON passed into stdin.
I searched and found this SO question, and learned kubectl command may be that kind of command that does not read stdin(am I right?).
I tried
cat yaml |xargs kubectl replace -f
but error returned:
the path "apiVersion:" does not exist
So is the ending short dash(-) syntax built for kubectl ONLY? or is some more common syntax of linux bash stdin pipe? Can some one explain why xargs not work here and I must place a short dash(-) at the end?
This is a reasonably common, but not universal, Un*x convention. (It is mentioned in the POSIX specification and so most non-Linux Unices will support it as well.)
The important detail here is that the kubectl ... -f
option expects a filename. If you have a file named x.yaml
, a more direct way to write what you've shown is just
kubectl replace -f x.yaml
Where you say -f -
, that ostensibly means "a file named -
", but kubectl
(along with many other tools) actually interprets this to mean "the process's standard input". For instance, you could use this for a very lightweight templating system, like
sed 's/TAG/1.2.3-20190103/g' x.yaml | kubectl replace -f -
For Un*x tooling in general, POSIX.1 states that, for many commands,
...an operand naming a file can be specified as '-', which means to use the standard input instead of a named file....
Some commands that support this include cat, grep, sort, and tar (not required by POSIX). One way to move a directory tree between two Linux machines, for instance, is to create a tar file on stdout, pipe that stream via ssh to a remote machine, and then unpack the tar file from stdin:
tar cf - . | ssh elsewhere tar xf - -C /other/dir
xargs is a tool that converts (most often) a list of filenames on standard input to command line arguments. For instance, find(1) can print a list of matching filenames to its stdout, so you could build a pipeline to delete shell backup files like
find . -name '*~' | xargs rm
You wouldn't usually use this with Kubernetes; your example tries to pass the YAML content itself as command-line arguments to kubectl
, for example. You could apply kubectl
across a directory tree with something like
find . name '*.yaml' | xargs -n1 kubectl apply -f
but since kubectl ... -f
also supports directory names (not a universal convention) you could do the same thing more directly as
kubectl apply -f . # where . is the current directory