Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Production vs Development environment variables. #543

Closed
clanstyles opened this issue May 12, 2018 · 34 comments
Closed

Production vs Development environment variables. #543

clanstyles opened this issue May 12, 2018 · 34 comments

Comments

@clanstyles
Copy link

What is the right way to store values in a deployment but switch them out for production? If I include secrets, do I mock the secrets with blank data and set them by hand? If the YAML for the secret changes, Skaffold would automatically update them. Some of these values aren't passwords, they might just be flags for "development" to switch out hostnames.

What's the recommended workflow for this?

@jstrachan
Copy link
Contributor

jstrachan commented May 15, 2018

if you use Helm for packaging up your application, you can put environment specific configuration values in your values.yaml file in your chart - then any installation of your chart can override any of those configuration values via helm install mychart --set foo.bar=123

On the Jenkins X project we use helm for packaging up applications and installing them in each environment and we're big fans of GitOps - so prefer to store these environment specific configuration values in a git repository - each environment gets its own git repository to manage those values in a values.yaml file - along with storing all the charts to be installed in the environment along with the versions of the charts to install.

Then to inject the values from values.yaml into your actual Deployment you can either expose the values as environment variables - or you can put the YAML inside a ConfigMap and mount it to the file system as a configuration file. e.g. if you are using Spring Boot you could mount the YAML from values.yaml as your application.yml file on your classpath

@dlorenc
Copy link
Contributor

dlorenc commented May 18, 2018

Let's use this issue to track the overall environment variable design/support. There have been a number of issues about this that I'll dupe against this bug.

@stevenbarragan
Copy link

There is helm secrets, I'm trying to figure out how to put it together with skaffold, has anybody tried it?

@cpoole
Copy link

cpoole commented Jun 27, 2018

This would be super helpful for us.

We have a static container that serves a react app. This app needs to be compiled/minified/etc when we go to dev through prod. But on our local machines we would like to skip the full compile and just run a continuous webpack server. Waiting a full minute for a total react rebuild isnt reasonable.

If we could pass a build arg to the dockerfile we could skip the react build in the dockerfile and this would be much more reasonable.

@bhack
Copy link

bhack commented Jun 28, 2018

What is the problem with profiles?

@Place1
Copy link

Place1 commented Aug 11, 2018

It'd be nice if skaffold would allow you to defined variables that are rendered into your manifests. These ideally could be global or profile specific and could be sourced from environment variables e.g.

apiVersion: skaffold/v1alpha2
kind: Config
profiles:
- name: prod
  # ...  
  deploy:
    kubectl:
      manifests: ./k8s/*
    values:
      namespace: "prod"
      domain: "myapp.com"
- name: feature-branch
  # ...  
  deploy:
    kubectl:
      manifests: ./k8s/*
    values:
      namespace: "${CI_ENVIRONMENT_SLUG}"
      domain: "${CI_ENVIRONMENT_SLUG}.myapp.com"

then your k8s manifests could have the following:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: myservice-ingress
  namespace: "${namespace:-default}"
spec:
  rules:
  - host: "myservice.${domain:-local}"
    http:
      paths:
      - path: /
        backend:
          serviceName: myservice
          servicePort: 80

I think this also allows skaffold to fill a nice middle ground between basic deployments with static manifests and helm deployments which adds a cluster component and multiple extra configuration files that feel like boilerplate when all you need is some basic template rendering.

@Place1
Copy link

Place1 commented Aug 28, 2018

What is the problem with profiles?

One limitation of profiles is that it requires you to hardcode values into skaffold.yaml which isn't desirable when the values are secrets.

This closed issue touched on a solution to this problem.

Also, I've found profiles to be very verbose. Consider the case where you want to change a docker build argument (as mentioned in #562) between development and production. If you used profiles for this then you'd be copy/pasting your development profile into a new 'production' profile and changing 1 value.

i'm not sure what the solution is but these are some things i've bumped into using skaffold

edit:
I should add that using environment variables for everything can be great in a CI environment where it's likely already standardized and setup for you, but in most other use-cases it can be really hard to use because you end up having to run commands like MY_ARG=value MY_OTHER_THING=value skaffold dev.

@stevenjm
Copy link
Contributor

stevenjm commented Sep 4, 2018

Another use case: The ability to interpolate environment variables within a skaffold.yaml would also be useful for builds. We have a build that makes use of a .npmrc with an authentication token that gets passed to Docker from Skaffold as a buildArg. (It is a multi-stage Docker build, so the image which uses this token never leaves the build machine.)

Rather than hard coding this in skaffold.yaml, it would be useful to be able to provide it from the environment. I've been using the following patch for testing, which works but is a hack:

diff --git a/pkg/skaffold/schema/v1alpha2/config.go b/pkg/skaffold/schema/v1alpha2/config.go
index e497490d..4a9735a2 100644
--- a/pkg/skaffold/schema/v1alpha2/config.go
+++ b/pkg/skaffold/schema/v1alpha2/config.go
@@ -17,6 +17,7 @@ limitations under the License.
 package v1alpha2

 import (
+       "github.com/GoogleContainerTools/skaffold/pkg/skaffold/util"
        "github.com/pkg/errors"
        yaml "gopkg.in/yaml.v2"
 )
@@ -223,6 +224,18 @@ func (c *SkaffoldConfig) Parse(contents []byte, useDefaults bool) error {
                return err
        }

+       for i, a := range c.Build.Artifacts {
+               for k, v := range a.DockerArtifact.BuildArgs {
+                       t, err := util.ParseEnvTemplate(*v)
+                       if err == nil {
+                               r, err := util.ExecuteEnvTemplate(t, map[string]string{})
+                               if err == nil {
+                                       c.Build.Artifacts[i].DockerArtifact.BuildArgs[k] = &r
+                               }
+                       }
+               }
+       }
+
        if useDefaults {
                if err := c.setDefaultValues(); err != nil {
                        return errors.Wrap(err, "applying default values")

I'm not sure what the best way is to solve this in a general way.

@bryanlarsen
Copy link
Contributor

What is the problem with profiles

My build section is 50 lines of YAML and only about half complete. One of the buildArgs is unique per developer, so I'd need to add 17 * 100 lines to my skaffold.yaml.

@nathkn
Copy link

nathkn commented Sep 17, 2018

Personally I'd be in favor of allowing all fields in the skaffold.yaml to be able to be evaluated as envTemplates, just for flexibility of workflows.

I think a separate but related issue being discussed here is simply that skaffold doesn't allow profiles to inherit much of the defined yaml, as is spelled out in #789, so it might make sense to move that discussion over there.

@arnaud-deprez
Copy link

I'm definetely in favour of allowing all fields to be templatized.
I can see different use cases at build or deploy time that can be parameterized depending the environment.

And IMOH, we should also consider default value for these parameters so if it is nothing is specify on dev workstation for example, default is applied. May bash syntax ${FOO:-fooDefault} is good candidate ?

@Place1
Copy link

Place1 commented Sep 20, 2018

an alternative to the bash syntax which might be nice considering skaffold.yaml already uses go templating might be '{{ .MyEnvVar | default "a-default-value" }}' using a custom template function.

@r2d4
Copy link
Contributor

r2d4 commented Oct 9, 2018

Some tools have built templating over skaffold. You might want to check them out

https://github.com/jkozera/j2skaffold is an example.

@RoryShively
Copy link
Contributor

I just opened an issue to continue the work on getting helm-secrets to work with skaffold
#1178

@brpaz
Copy link

brpaz commented Oct 21, 2018

A common way to define environment variables during development is using a ".env" file. Docker-compose supports loading env files by default. It would be great if we can have the same with skaffold.

It could be added to the "docker" section of the skaffold.yaml file like:

docker:
    env_file: "./.env"

@Place1
Copy link

Place1 commented Oct 27, 2018

I've been maintaining a small fork that addresses some of the things in this issue. It allows you to:

https://github.com/Place1/skaffold#things-ive-added

  1. use environment variables for buildArgs
  2. use environment variables and templates for the kubectl deployer
  3. rollout status for deployments, statefulsets and daemon sets (output a message when the deployment rollout is complete #459)

It looks a bit like this: https://github.com/Place1/skaffold/blob/master/examples/manifest-templating/skaffold.yaml

I think it'd be easy to add support for a .env file as @brpaz suggested. I'm also keen to add a multi CLI flag such as --set <variable>=<value> so that users can define these variables in the environment, a flag or file (in order of precedence).

@nagonzalez
Copy link

@Place1 I'd love to give your fork a shot but I'm unable to get it to work. Below are steps I took to build. Am I missing something?

build steps:

git clone https://github.com/Place1/skaffold.git
cd skaffold
go get -u -d github.com/Place1/skaffold
make install

skaffold.yml:

apiVersion: skaffold/v1alpha5
kind: Config
build:
  artifacts:
  - image: aws_ecr/target
    docker:
      buildArgs:
          PYPI_INDEX: '{{ .PYPI_INDEX }}'
      dockerfile: ./build/Dockerfile

@Place1
Copy link

Place1 commented Nov 3, 2018

@nagonzalez here's how I run skaffold.

  1. clone the repo into ~/go/src/github.com/Place1/skaffold
  2. cd ~/go/src/github.com/Place1/skaffold/cmd/skaffold
  3. go build ./skaffold.go
  4. use the built binary ./skaffold

@Place1
Copy link

Place1 commented Nov 5, 2018

perhaps https://github.com/kontena/mortar cloud be used as a deployer. it seems to satisfy most of the features being raised in this issue.

@fikriauliya
Copy link

My issue is similar to @cpoole :

  • The generated Docker image for development and production should differ
  • The development docker run the app in development mode (faster compile)
  • The production docker needs more complex build (longer compile). Currently we offload this process to CloudBuild (configured in cloudbuild.yaml)

I wish Skaffold can:

  • Have different build mode based on environment
  • Read cloudbuild.yaml for production build

@cpoole
Copy link

cpoole commented Dec 7, 2018

@fikriauliya I fixed my issue with docker args
set the local_build arg to true by default and then in your run block do the following:

RUN if [ "$local_build" == "false" ]; then \
             npm build prod stuff; \
         fi;

and in our jenkins build we pass local_build false

@jakolehm
Copy link

jakolehm commented Dec 9, 2018

@Place1 I heard rumours that @jnummelin is working on mortar support.

@matti matti mentioned this issue Dec 22, 2018
@bholemt
Copy link

bholemt commented Jan 2, 2019

if docker build arg command can pick values up from environment, then why shouldn't skaffold. skaffold should support all arguments to docker build in the same standard manner. why try to reinvent the whole thing and plug in one more tool? .env file is also another new way of doing the same thing. it doesn't work for private keys.

@rcoh
Copy link

rcoh commented Feb 28, 2019

It would be nice if you could define the environment variables in the profile rather than having to pass them in. Ideally I could just do skaffold run --profile staging but I think instead I need to maintain to different sets of environment variable files and use them appropriately to get access to the env var templating?

@tibbon
Copy link

tibbon commented Apr 19, 2019

Definitely need this. Is there anything something needs to help make this happen?

@stevenpall
Copy link

@Place1 I just ran into the variable substitution in buildArgs issue and came across your fork which attempts to add this functionality. Unfortunately, I'm unable to actually run your version of skaffold after compiling it. I get the following errors running skaffold dev or skaffold run:

Error: reading configuration: Config version out of date: run `skaffold fix`
FATA[0000] reading configuration: Config version out of date: run `skaffold fix`

Running skaffold fix, I get

ERRO[0000] Unable to parse config

I thought this might be due to my skaffold.yaml apiVersion. I was using skaffold/v1beta8 but have also tried other versions all the way back to skaffold/v1alpha4 to no avail. If this is simply an API version issue, I was wondering if you'd be able to rebase your fork against upstream so that the latest API version should work.

On a related note, do you think submitting these changes as a PR to upstream would be appropriate? It seems like a lot of people are looking for this functionality to be added to the core product.

Thanks!

@Place1
Copy link

Place1 commented Apr 22, 2019 via email

@demisx
Copy link
Contributor

demisx commented May 30, 2019

This is a highly desirable feature for our team as well. Using the good old envsubst as a workaround in the meantime:

# In skaffold.yaml
...
docker:
    dockerfile: app/api/Dockerfile
    target: dev-env
    buildArgs:
        AWS_ACCOUNT_ID: "$AWS_ACCOUNT_ID"
        NAMESPACE: "$NAMESPACE"
$ envsubst < skaffold.yaml > skaffold.gen && skaffold dev -f=skaffold.gen --port-forward=false

@reegnz
Copy link

reegnz commented Jun 17, 2019

@demisx you dont need envsubst for that anymore, skaffold can already template buildArgs. It's been in 0.29.0: https://github.com/GoogleContainerTools/skaffold/releases/tag/v0.29.0:

Allow environment variables to be used in docker build argument #1912

Only restriction is that you will have to build through the docker cli, not the docker API:

build:
  local:
    useDockerCLI: true

I guess this issue is more about the kubernetes manifests, and not the docker build.

@demisx
Copy link
Contributor

demisx commented Jun 19, 2019

@reegnz Thank you! Worked like a charm!

# In skaffold.yaml
    ...
    build:
      local:
        useDockerCLI: true
      artifacts:
        - image: my-docker-image
          docker:
            dockerfile: path/to/Dockerfile
            buildArgs:
              DOCKER_ARG_1: "{{.ENV_VAR_1}}"
              DOCKER_ARG_2: "{{.ENV_VAR_2}}"
              ...

@dkirrane
Copy link

dkirrane commented Jun 26, 2019

Hi, Looking to use Env variables inside Helm deployment

This currently doesn't work for var1 & var2 below

apiVersion: skaffold/v1beta11
kind: Config

deploy:
 helm:
    releases:
      - name: my-chart
        chartPath: ./helm/my-chart
        setValueTemplates:
          image.repository: "{{.IMAGE_NAME}}"
          image.tag: "{{.VERSION}}"
        overrides:
            var1: {{.ENV_VAR_1}}
            var2: {{.ENV_VAR_2}}

@demisx
Copy link
Contributor

demisx commented Aug 21, 2019

Are the environment variables currently supported deploying plain YAML resources and not Helm releases?

@tejal29
Copy link
Contributor

tejal29 commented Oct 2, 2019

Related to #2849

@tejal29
Copy link
Contributor

tejal29 commented Oct 2, 2019

I am going to close this and we should track this in #2849

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests