-
Notifications
You must be signed in to change notification settings - Fork 16
Support distroless (and distroful) Envoy images #391
Conversation
Secret is assumed to exist at this point. Future commits will create the secret. Co-Authored-By: sarahalsmiller <[email protected]>
This allows our Gateway image to run on envoy-distroless 🎉 Co-Authored-By: sarahalsmiller <[email protected]>
885a2e2
to
2975768
Compare
We create a secret per gateway since the secret must be in the same namespace as the gateway pod in order to reference it in a volume mount
78b6a56
to
581cff7
Compare
55ba961
to
46f6a63
Compare
This branch will not pass conformance tests until we can pin to consul-k8s v0.49.0, which hasn't been released yet. This is because of a dependency on RBAC changes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Personal review
Note Conformance tests won't pass until consul-k8s v0.49.0, which contains the necessary RBAC changes for create/update
Secret
, is released and consumed
@@ -94,8 +94,10 @@ rules: | |||
resources: | |||
- secrets | |||
verbs: | |||
- create |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The controller needs to be able to create Secrets
to hold the Consul CA cert for each gateway Deployment
. I used a Secret
to be consistent w/ consul-k8s which uses a Secret
for the same value.
internal/k8s/builder/gateway.go
Outdated
Name: api.HTTPCAFile, | ||
Value: consulCALocalFile, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This adds the path to the CA cert in the pod's environment. This was previously done inside the shell script below as
export CONSUL_CACERT={{ .ConsulCAFile }}
internal/k8s/builder/gateway.go
Outdated
Command: []string{"/bootstrap/consul-api-gateway", "exec"}, | ||
Args: b.execArgs(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of running the shell with one giant argument that was our startup script, we're now running consul-api-gateway exec
with many small arguments/flags
Secret: &corev1.SecretVolumeSource{ | ||
SecretName: b.gateway.Name, | ||
Items: []corev1.KeyToPath{ | ||
{ | ||
Key: "consul-ca-cert", | ||
Path: consulCAFilename, | ||
}, | ||
}, | ||
DefaultMode: nil, | ||
Optional: pointer.Bool(false), | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of creating an empty volume and then having our shell script insert the CA cert, we now source the volume's contents from the Secret
containing the CA cert, which is created further down in internal/k8s/reconciler/deployer.go
// gwContainerArgsTpl is the template for the command arguments executed in the Envoy container. | ||
// The resulting args are split on \n to obtain a []string for the pod spec's args. | ||
// Note: Make sure not to leave whitespace at the beginning or end of any line. | ||
const gwContainerArgsTpl = ` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Left the godoc here to explain since the template looks kinda weird now.
Basically, the flag name and its value are expected to be two separate items in the args
array for the pod template. It was still easier to compile the list of args using a template like we were before since the other options is a big string builder with a bunch of conditionally-included fmt.Sprintf
s.
@@ -388,15 +389,19 @@ func (g *gatewayClient) Update(ctx context.Context, obj client.Object) error { | |||
return nil | |||
} | |||
|
|||
func (g *gatewayClient) CreateOrUpdateDeployment(ctx context.Context, deployment *apps.Deployment, mutators ...func() error) (bool, error) { | |||
operation, err := controllerutil.CreateOrUpdate(ctx, g.Client, deployment, func() error { | |||
func multiMutatorFn(mutators []func() error) func() error { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
abstracting this out into a function wrapper since we needed the same logic in one more place now for CreateOrUpdateSecret
internal/k8s/reconciler/deployer.go
Outdated
@@ -52,6 +54,10 @@ func (d *GatewayDeployer) Deploy(ctx context.Context, gateway *K8sGateway) error | |||
return err | |||
} | |||
|
|||
if err := d.ensureSecret(ctx, gateway.Gateway); err != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can see here that we create the Secret
containing the CA Cert before we create the Deployment
that needs to reference the Secret
for the contents of one of its volumes.
// MergeService merges a gateway service a onto b and returns b, overriding all of | ||
// the fields that we'd normally set for a service deployment. It does not attempt | ||
// to change the service type | ||
func MergeService(a, b *corev1.Service) *corev1.Service { | ||
if !compareServices(a, b) { | ||
a.Annotations = b.Annotations | ||
b.Annotations = a.Annotations |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seemed like an oversight. Not sure if it's had any material impact on our software or not up until now
@@ -177,12 +177,39 @@ type MeshServiceList struct { | |||
Items []MeshService `json:"items"` | |||
} | |||
|
|||
func MergeSecret(a, b *corev1.Secret) *corev1.Secret { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ripped off from the MergeService
logic below. Just need to determine what the final state of the Secret
should be if we're modifying one that already exists.
export CONSUL_CACERT=/consul/tls/ca.pem | ||
cat <<EOF >/consul/tls/ca.pem | ||
CONSUL_CA_MOCKED | ||
EOF |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks a little different from other tests, should any of this be reflected in the new CA cert logic?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The CONSUL_CACERT
envvar is now added to the pod spec below in this case, and the cert content ("CONSUL_CA_MOCKED" here) would now be deployed into a secret that the volume mount below references.
I did refine the code a bit just now to only include the envvar and create the secret when the CA is actually required, so now it's clearer that the resulting deployment for this test case which does require the CA is different from the others which don't require the CA.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Holding approval until conformance tests are updated to consul-k8s v0.49.0 and passing (added pr/conformance
label so it's clear this is currently blocked on failing tests), but approach LGTM.
Should this update or add a CI test with distroless images as #152 did? |
@mikemorris that gets difficult because consul-k8s doesn't support distroless yet, so we can't just set |
096dcd4
to
9df8349
Compare
Changes proposed in this PR:
Remove dependency on shell by:
Secret
containing the Consul CA cert for each gateway deploymentSecret
export
orexec
that we previously depended onHow I've tested this PR:
apiGateway.enabled: true
) and a build of this branchGatewayClassConfig
to useenvoyproxy/envoy-distroless
instead ofenvoyproxy/envoy
Gateway
and verify that it works correctlyHow I expect reviewers to test this PR:
See above
Checklist: