Skip to content

Ability to set pod environment variables on cluster resource#1794

Merged
sdudoladov merged 11 commits into
zalando:masterfrom
dmvolod:issue-1566
Apr 11, 2022
Merged

Ability to set pod environment variables on cluster resource#1794
sdudoladov merged 11 commits into
zalando:masterfrom
dmvolod:issue-1566

Conversation

@dmvolod

@dmvolod dmvolod commented Feb 22, 2022

Copy link
Copy Markdown
Contributor

Fixes #1566
Closes #1209
Closes #1422
Closes #907
Closes #1807

Please pay attention, that this PR implementing an individual []EnvVar option to the cluster CR and has higher priority to the cluster pod_environment_secret and pod_environment_configmap options.

TODO (after approach approve)

  • Doc changes
  • Unit testing

@dmvolod

dmvolod commented Feb 28, 2022

Copy link
Copy Markdown
Contributor Author

@FxKu could you please to have a look at the fix approach. If it will be suitable, I will add docs and unit-test for it. Thanks in advance.

@cdmikechen

cdmikechen commented Mar 4, 2022

Copy link
Copy Markdown
Contributor

In CRD, Is there possible to add only some environment variables to pod? for example

spec:
  env:
    - name: ENV_1
      value: VALUE_1

@dmvolod

dmvolod commented Mar 4, 2022

Copy link
Copy Markdown
Contributor Author

In CRD, Is there possible to add only some environment variables to pod? for example

Not sure, that's good approach as will need to support both setup for predefined ConfigMap/Secret and current one. Common way much better and didn't overload CR if it's not needed

@dmvolod

dmvolod commented Mar 17, 2022

Copy link
Copy Markdown
Contributor Author

@FxKu could you please to find a time and have a look at the fix approach. If it will be suitable, I will add docs and unit-test for it. Thanks in advance.

@FxKu

FxKu commented Mar 21, 2022

Copy link
Copy Markdown
Contributor

Hey @dmvolod, while it looks elegant at first, I don't think it should be solved like this because only one way is possible - global config map or the need to add config maps for each cluster. The latter will be tedious if you need cluster-specific variables only for a handful of clusters while the rest of your fleet should be configured in the same way. Better have env variables from cluster-specific config maps / secrets to overwrite global ones - like we do it with other options, too. Probably, partly overwriting (in case of same env variables) will be most convenient.

Comment thread pkg/cluster/k8sres.go Outdated
@dmvolod

dmvolod commented Mar 21, 2022

Copy link
Copy Markdown
Contributor Author

Hey @dmvolod, while it looks elegant at first, I don't think it should be solved like this because only one way is possible - global config map or the need to add config maps for each cluster. The latter will be tedious if you need cluster-specific variables only for a handful of clusters while the rest of your fleet should be configured in the same way. Better have env variables from cluster-specific config maps / secrets to overwrite global ones - like we do it with other options, too. Probably, partly overwriting (in case of same env variables) will be most convenient.

Thanks for feedback, @FxKu . I'm also agree with approach to have a ConfigMap/Secret parameter for each cluster individually if needed and present. If you agree with this approach I will add these options to the CRD and implement logic to overwrite global parameters if CR parameters are present and find in the cluster ConfigMap/Secret.

@cdmikechen

Copy link
Copy Markdown
Contributor

I‘m looking forward to the progress of this PR.
I have similar needs at present. We need to deploy multiple Postgres to different namespaces and back up to different minio services.

@FxKu

FxKu commented Mar 23, 2022

Copy link
Copy Markdown
Contributor

@cdmikechen note that you can already run multiple operators next to each other configured differently. They could either watch only one namespace or you define a CONTROLLER_ID in deployment and manifests to specify ownership over clusters.

@cdmikechen

cdmikechen commented Mar 23, 2022

Copy link
Copy Markdown
Contributor

@cdmikechen note that you can already run multiple operators next to each other configured differently. They could either watch only one namespace or you define a CONTROLLER_ID in deployment and manifests to specify ownership over clusters.

@FxKu
Thanks~ It looks like a good solution for my needs. I used to deploy only one operator to manage all namespaces, which will really bring me some troubles.
I'll try it later and see if there will be any other problems.

@FxKu FxKu added this to the 1.9 milestone Mar 24, 2022
@dmvolod

dmvolod commented Mar 25, 2022

Copy link
Copy Markdown
Contributor Author

@FxKu please have a look at the new approach with individual []EnvVar option again and has a higher priority to the global cluster options. Thanks in advance.

@gc-jro

gc-jro commented Mar 28, 2022

Copy link
Copy Markdown

Hi @dmvolod, thanks for this PR.

Do you still plan to add the possibility to refer to a cluster specific secret for environment variables in the postgresql custom resource?

I’ve a slightly different set of requirements, where we maintain our cluster configuration in Git, but aren’t allowed to store confidential information (like wal-g backup settings) in plain text. To circumvent this, we use SealedSecrets [1] to store the settings encrypted in Git. In our k8s cluster the SealedSecrets get decrypted into normal secrets that can be used by the cluster. I’ve also the requirement that we’ve multiple postgresql clusters in the same namespace, and the need that they use different wal-g backup settings.

Therefore, it would be great if in addition to use individual []EnvVar settings in the postgresql CR, there would be an option to specify an individual secret in the postgresql CR that would be used for populating environment variables.
If you aren’t planning to add this option that’s totally fine, then I’ll ask my boss to get some time to patch the functionality in myself.

[1] https://github.com/bitnami-labs/sealed-secrets

@dmvolod

dmvolod commented Mar 29, 2022

Copy link
Copy Markdown
Contributor Author

Hi @gc-jro !

Yes, sure. Could you please to have a look at the EnvVar struct which is including EnvVarSource field and supports referencing to the Secret (SecretKeyRef).
https://github.com/kubernetes/api/blob/master/core/v1/types.go#L1977-L2015

What do you think about it?

@gc-jro

gc-jro commented Mar 29, 2022

Copy link
Copy Markdown

Ah I see. Thanks a lot for clearing that up for me. I really like it, it'll solve all my problems 😄

I'll just have to define something like

apiVersion: v1
kind: Secret
metadata:
  name: wal-g-envs
  namespace: yyy
data:
  BACKUP_NUM_TO_RETAIN: xxx
  ...
---
apiVersion: "acid.zalan.do/v1"
kind: postgresql
metadata:
  name: wal01-postgres-cluster
  namespace: yyy
spec:
  teamId: "wal01"
  volume:
    size: 20Gi
  env:
    - name: BACKUP_NUM_TO_RETAIN
      valueFrom:
        secretKeyRef:
          key: BACKUP_NUM_TO_RETAIN
          name: wal-g-envs
  ...

to forward the values from the secret to the database. Very neat.

Thank you very much. I can't wait to give it a spin once its merged into master.

@dmvolod dmvolod changed the title Ability to set pod_environment_secret and pod_environment_configmap on cluster resource Ability to set pod environment variables on cluster resource Mar 30, 2022
@FxKu

FxKu commented Mar 31, 2022

Copy link
Copy Markdown
Contributor

Thank @dmvolod ! Like the new approach much better. As you already pointed out, docs and unit test are the remaining bits to get this merged.

@FxKu FxKu removed this from the 1.9 milestone Apr 4, 2022
@FxKu

FxKu commented Apr 6, 2022

Copy link
Copy Markdown
Contributor

I got it working now. See my gist: https://gist.github.com/FxKu/0b4e0641f1c846a2a0edbc2c6ee6a0cc
Because I changed the expected list of []v1.EnvVar in TestPodEnvironmentConfigMapVariables the comparison with getPodEnvironmentConfigMapVariables result did not work anymore. But maybe it should be a test on its own together with fetching variables for the secrets and test clearly what overrides what (and also make it clearer in the docs, but I can help there).

@dmvolod

dmvolod commented Apr 6, 2022

Copy link
Copy Markdown
Contributor Author

I got it working now. See my gist: https://gist.github.com/FxKu/0b4e0641f1c846a2a0edbc2c6ee6a0cc
Because I changed the expected list of []v1.EnvVar in TestPodEnvironmentConfigMapVariables the comparison with getPodEnvironmentConfigMapVariables result did not work anymore. But maybe it should be a test on its own together with fetching variables for the secrets and test clearly what overrides what (and also make it clearer in the docs, but I can help there).

Thanks for test, @FxKu
Probably, we should move EnvVar logic to the generateSpiloPodEnvVars and utilize another tests for that. What do you think about it?

Comment thread pkg/cluster/k8sres.go Outdated
Comment thread pkg/cluster/k8sres.go Outdated
Comment thread pkg/cluster/k8sres.go Outdated
Comment thread pkg/cluster/k8sres.go Outdated
Comment thread pkg/cluster/k8sres.go Outdated
}
}
return false
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, it might be even better to do isEnvVarPresent in generateSpiloPodEnvVars, too, instead of appending duplicate variables and resolving it later with deduplicateEnvVars.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix logic, please review.

Comment thread pkg/cluster/k8sres.go Outdated
envVarConstant: "WAL_S3_BUCKET",
envVarValue: "custom-s3-bucket",
},
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

custom variables should not be pre-pended so this addition is also obsolete.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is approach from the following point

  • A custom variable called like a hard-coded variable that can be overridden (like WAL_S3_BUCKET)

},
},
},
},

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test should incl. 3 kinds of variables - like in my gist.

  1. A custom variable called like a hard-coded variable that cannot be overridden (I uses KUBERNETES_SCOPE_LABEL)
  2. A custom variable called like a hard-coded variable that can be overridden (like WAL_S3_BUCKET)
  3. And a custom variable that's not in the list of hard-coded variables. And there we can test, if a variable from c.Spec.Env overwrites on from environment ConfigMap and/or Secret.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, thanks will implement this options.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Implemented tests, please review.

@FxKu

FxKu commented Apr 7, 2022

Copy link
Copy Markdown
Contributor

Ok aside from missing unit tests there's one problem that has to be fixed. Right now we only append env vars and rely on deduplicateEnvVars to come up with the right set in the end. That is, it will take only the first mention of a variable into account except when the variable starts with WAL_ or LOG_. Then it will take the last mention.

This logic will not work anymore now that we have a third layer, the cluster-specific Env.

  1. It MUST NOT override our hard-coded set of variables from generateSpiloPodEnvVars up until this line. Only append after that.
  2. MUST override the PodEnvironmentConfigMap and/or Secret. So we append before that. But then WAL_ or LOG_ settings from PodEnvironmentConfigMap and/or Secret would override c.Spec.Env because of the logic in deduplicateEnvVars.

That's why I suggested that we should not simply append to the list of envVars but only do so if the key does not exists yet. So basically what you partly did with isEnvVarPresent. But instead of adding this check everywhere, we better write an append function for EnvVar lists that incl. this check. Finally, deduplicateEnvVars can be removed.

@dmvolod

dmvolod commented Apr 7, 2022

Copy link
Copy Markdown
Contributor Author

That's why I suggested that we should not simply append to the list of envVars but only do so if the key does not exists yet. So basically what you partly did with isEnvVarPresent. But instead of adding this check everywhere, we better write an append function for EnvVar lists that incl. this check. Finally, deduplicateEnvVars can be removed.

Does it means that we need to utilize new appendEnvVars function everywhere inside the generateSpiloPodEnvVars and related functions?

@FxKu

FxKu commented Apr 7, 2022

Copy link
Copy Markdown
Contributor

Yes, inside generateSpiloPodEnvVars. The flow should be:

  1. envVars := []v1.EnvVar{...}
  2. append spiloCompathWalPathList
  3. append c.Spec.Env
  4. fetch from getPodEnvironmentSecretVariables and append
  5. fetch from getPodEnvironmentConfigMapVariables and append
  6. fetch from generateCloneEnvironment and append
  7. fetch from generateStandbyEnvironment and append
  8. append WAL_ LOG_ AZURE_ etc. variables

I don't see why anything related to spilo env vars should happen outside of generateSpiloPodEnvVars. Noticed that deduplicateEnvVars is also used for sidecars. So maybe it can stay then.

@dmvolod

dmvolod commented Apr 7, 2022

Copy link
Copy Markdown
Contributor Author

Yes, inside generateSpiloPodEnvVars. The flow should be:

  1. envVars := []v1.EnvVar{...}
  2. append spiloCompathWalPathList
  3. append c.Spec.Env
  4. fetch from getPodEnvironmentSecretVariables and append
  5. fetch from getPodEnvironmentConfigMapVariables and append
  6. fetch from generateCloneEnvironment and append
  7. fetch from generateStandbyEnvironment and append
  8. append WAL_ LOG_ AZURE_ etc. variables

I don't see why anything related to spilo env vars should happen outside of generateSpiloPodEnvVars. Noticed that deduplicateEnvVars is also used for sidecars. So maybe it can stay then.

Thanks for idea, please have a look at the code. Added functions and changed from plain append to the new one.

@FxKu

FxKu commented Apr 11, 2022

Copy link
Copy Markdown
Contributor

👍

1 similar comment
@sdudoladov

Copy link
Copy Markdown
Contributor

👍

@sdudoladov
sdudoladov merged commit 9bcb25a into zalando:master Apr 11, 2022
@FxKu

FxKu commented Apr 11, 2022

Copy link
Copy Markdown
Contributor

Thanks @dmvolod for your contribution. Good collaboration!

@dmvolod

dmvolod commented Apr 11, 2022

Copy link
Copy Markdown
Contributor Author

Thanks @FxKu and @sdudoladov for review and ideas.

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

Labels

None yet

Projects

None yet

5 participants