1

I've created a Makefile to export a kubeconfig from fixed path like:

myproj
 - .kube     //folder
     config    //file which contain the config
 - Makefile.  //same level as .kube folder

Now when I'm running from the terminal the following it works, I mean if I run kubectl get ns I got results which means that it configure successfully!

export KUBECONFIG=/Users/i33333/projects/app-test/v-app/.kube/config

I've created a makefile target like following

kube-cfg:
    export KUBECONFIG=$(PWD)/.kube/config

When execute the target I see in the terminal

export KUBECONFIG=/Users/i33333/projects/app-test/v-app/.kube/config

which exactly the same as doing that manually but when when I run kubectl get ns

I got error:

error: no configuration has been provided, try setting KUBERNETES_MASTER environment variable

I dont understand why it dosent work when I run it from makefile and works when I run it from the terminal manually ? any idea I try to change and use also the $(CURRDIR) which doesnt help

update

I've tried like suggested which doesnt works

KUBECONFIG=$(PWD)/.kube/config


kube-cfg:
    export $(KUBECONFIG)

update2

If I do it like this

KUBECONFIG := $(PWD)/kube/config.yaml
tgt1:
    @export KUBECONFIG=$(KUBECONFIG) && kubectl get ns

I was able to see the ns when running the makefile tgt1: but if now I want to run it from the terminal kubectl get ns I get the same error `error: no configuration has been provided, try setting KUBERNETES_MASTER environment variable, I want to configure it from the makefile

NSS
  • 755
  • 1
  • 11
  • 30

2 Answers2

1

The problem is that makefile recipe creates new environment, which is destroyed after finishing recipe.

If you want to use kubernetes tools after calling make, more appropriate tool in your scenario is using source command. It applies in your current environment all changes made in script passed as parameter:

$ source setupenv.sh
$ kubectl get ns # should be no problem
$ make someting # even using kubectl inside make shouldn't be a problem

However if you want to use kubectl in make scripts, then create something like:

recipe :
      source setupenv.sh && kubectl get ns
# or 
recipe2 :
      export KUBECONFIG=$(PWD)/.kube/config && kubectl get ns

UPDATE:

I thought config file is a script. So you should prepare shell script setting up environment, for example setupenv.sh:

#!/bin/bash
export KUBECONFIG=$(PWD)/.kube/config
Nabuchodonozor
  • 704
  • 1
  • 6
  • 13
  • sorry I dont understand it, I try source with the path and I got error, could you update your answer with my contexts ? – NSS May 04 '20 at 11:50
  • I dont want to use kubectl in my make , I just want to config the env and use it after in the terminal – NSS May 04 '20 at 11:51
  • Thanks, so I must define an addition script, I cannot run it from the makefile ? – NSS May 04 '20 at 11:56
  • @NinaS If you want to use it inside make recipe (without `source` before `make`), for each line environment must be setup. So I recommend to do it manually before make usage. – Nabuchodonozor May 04 '20 at 11:58
  • I tried both recipe and 2 and it doesnt works for me :( ...did you try that ? – NSS May 04 '20 at 12:17
  • do you have k8s cluster? that you can try it ? as this is not working and I dont have clue – NSS May 04 '20 at 12:20
  • I'm not familiar with kubernetes, I give you advice regarding make and shell usage, the output says, the variable `KUBERNETES_MASTER` should be configured, so are you sure `KUBECONFIG` is the right environment variable? – Nabuchodonozor May 04 '20 at 12:22
  • yes KUBECONFIG but I tried also with KUBERNETES_MASTER which doesnt works – NSS May 04 '20 at 12:26
  • @NinaS You can easily check if environment is properly setup, by putting env in recipe2 like: `export KUBECONFIG=$(PWD)/.kube/config && env && kubectl get ns` and checking the output – Nabuchodonozor May 04 '20 at 12:30
  • you right!, if I run it with `&&` get ns I see the list of `ns` but after the command finished and I run it from the terminal it doesnt work :( – NSS May 04 '20 at 12:36
  • what you sugget to do ? what is the best option to handle it ? is there a way to avoid the shell file ? – NSS May 04 '20 at 12:37
  • @NinaS Ok, so I think you misunderstood my answer. You cannot use pure `make` solution and then use kubectl in shell, because environment was setup only inside Makefile recipe. To use kubectl in your shell, you should only use `source` script instead of `make`. There is no easier solution, the question is why you want Makefile script but not shell script - which is more appropriate – Nabuchodonozor May 04 '20 at 12:40
  • I've create file `setenv.sh` sibling to the makefile and run the make target which contain `source setenv.sh` and I got error : make: source: No such file or directory , any idea? – NSS May 04 '20 at 12:48
  • @NinaS What does sibling file mean? The output clearly says that `source` get , (comma) as parameter. – Nabuchodonozor May 04 '20 at 12:51
  • You should not use `source`. `source` is a bash-specific feature. It is not a POSIX standard shell operation and will not be present in shells other than bash. You should use `.` instead, as in: `. setenv.sh`. – MadScientist May 04 '20 at 13:07
  • which mean like `recipe : .setupenv.sh` , this is also doesnt works, can you please update your answer what I should try exactly ? im bit confused ... – NSS May 04 '20 at 13:13
  • @NinaS MadScientist has comment that using `. ` (dot and space) is more portable way of doing what `source` command does. The answer is that you cannot do what you want only with make command – Nabuchodonozor May 04 '20 at 13:21
  • @MadScientist - so there is no way to do it with `makefile` ? see my update 2 – NSS May 04 '20 at 13:22
  • @Nabuchodonozor - Ok if I add a script file that the make will execute it, this will not work either? – NSS May 04 '20 at 13:23
  • @NinaS you tried `.setupenv.sh` (all one word). That's not what I wrote. I wrote `. setupenv.sh` (two words, `.` followed by your script name). – MadScientist May 04 '20 at 13:25
  • @NinaS No, everything called inside Makefile script will setup environment only inside Makefie script, no matter if it is shell statement or called script. – Nabuchodonozor May 04 '20 at 13:26
  • @MadScientist - I tried now with `. setupenv.sh` and the script is running but the env still not configured ....any idea? – NSS May 04 '20 at 13:27
  • 1
    @NinaS correct there is no way of doing this via `make`. It's not a deficiency in `make`. This is the way all programs in POSIX/UNIX systems work. When you start a new program that program inherits the environment of the parent program. However, it is not ever possible for the child program to modify the environment of the parent program. It doesn't matter if that program is `make`, a new shell, or some other program you wrote yourself. It can't be done. This has been true for the 50 years UNIX has existed. – MadScientist May 04 '20 at 13:28
1

When you run make the recipe is executed in a shell that is forked from make process. Also-recipes spanning multiple, each line (unless chained over newline escape) also gets its own shell child process. This effectively means, whatever happens (shell variable assignments or exports) in any of these shells, has no impact on the make itself or other recipe lines.

You could define for instance a make variable (as you have done in the update) and then you can set that in an environment for any command (somecmd) you are trying to run, e.g.:

some_target:
    export KUBECONFIG=$(KUBECONFIG); somecmd

or:

some_target:
    KUBECONFIG=$(KUBECONFIG) somecmd

In that case KUBECONFIG refers to a make variable, like the one you've defined above:

KUBECONFIG := $(PWD)/.kube/config

I.e. like this:

KUBECONFIG := $(PWD)/.kube/config

all: tgt1 tgt2

tgt1:
        @export KUBECONFIG=$(KUBECONFIG); echo "KUBECONFIG is $${KUBECONFIG}"

tgt2:
        @KUBECONFIG=$(KUBECONFIG) sh -c 'echo KUBECONFIG is $${KUBECONFIG}'

Yielding:

$ make
KUBECONFIG is /tmp/.kube/config
KUBECONFIG is /tmp/.kube/config

So, if you're after something that does persists also after the make is done, you need to write it out. E.g. a wrapper, such such as:

KUBECONFIG := $(PWD)/kube/config.yaml

.PHONY: call

# run callme.sh being the first prerequisite.
call: callme.sh
    ./$<

# creates and sets exec bit on rule target here being callme.sh
callme.sh:
    @echo -e '#!/bin/bash\nKUBECONFIG=$(KUBECONFIG) kubectl get ns' > $@
    chmod +x $@

This make you can run make and target call calls the wrapper... and you're also left with a wrapper callme.sh you can run after make is done.

Ondrej K.
  • 8,841
  • 11
  • 24
  • 39
  • Thanks, what should I put in the `$(KUBECONFIG)` ? – NSS May 04 '20 at 11:54
  • Sorry, I've omitted a bit when typing and the syntax was actually off. – Ondrej K. May 04 '20 at 12:53
  • No, do not add the `&&` defining variable(s) before command is called, makes that variable (exports it) to the environment of the command (and only that process and its children) being executed. The `&&` splits two commands in a pipeline just like `;` would. You either have to `export` and then call (`tgt1`) or set and call at once (`tgt2`). – Ondrej K. May 04 '20 at 13:35
  • But in any case... that is only for running anything inside a make recipe. You cannot have make export variable back into the shell you've executed it from. You can have it generate a wrapper script that can be called for instance. – Ondrej K. May 04 '20 at 13:42
  • Do you think that there is a way to do it with make, any way ? what do you mean by generated wrapper? – NSS May 04 '20 at 13:43
  • You mean to run `make something` and have it define / `export` environmental variable for subsequent execution of anything? No, that cannot be done. – Ondrej K. May 04 '20 at 13:48