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

feat: support envoyproxy & ratelimit deployment container env configu… #1363

Merged
merged 4 commits into from
Apr 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions api/config/v1alpha1/shared_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,11 @@ type KubernetesPodSpec struct {

// KubernetesContainerSpec defines the desired state of the Kubernetes container resource.
type KubernetesContainerSpec struct {
// List of environment variables to set in the container.
//
// +optional
Env []corev1.EnvVar `json:"env,omitempty"`

// Resources required by this container.
// More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
//
Expand Down
7 changes: 7 additions & 0 deletions api/config/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,131 @@ spec:
description: Container defines the resources and securityContext
of container.
properties:
env:
description: List of environment variables to set
in the container.
items:
description: EnvVar represents an environment variable
present in a Container.
properties:
name:
description: Name of the environment variable.
Must be a C_IDENTIFIER.
type: string
value:
description: 'Variable references $(VAR_NAME)
are expanded using the previously defined
environment variables in the container and
any service environment variables. If a variable
cannot be resolved, the reference in the input
string will be unchanged. Double $$ are reduced
to a single $, which allows for escaping the
$(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will
produce the string literal "$(VAR_NAME)".
Escaped references will never be expanded,
regardless of whether the variable exists
or not. Defaults to "".'
type: string
valueFrom:
description: Source for the environment variable's
value. Cannot be used if value is not empty.
properties:
configMapKeyRef:
description: Selects a key of a ConfigMap.
properties:
key:
description: The key to select.
type: string
name:
description: 'Name of the referent.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Add other useful fields. apiVersion,
kind, uid?'
type: string
optional:
description: Specify whether the ConfigMap
or its key must be defined
type: boolean
required:
- key
type: object
x-kubernetes-map-type: atomic
fieldRef:
description: 'Selects a field of the pod:
supports metadata.name, metadata.namespace,
`metadata.labels[''<KEY>'']`, `metadata.annotations[''<KEY>'']`,
spec.nodeName, spec.serviceAccountName,
status.hostIP, status.podIP, status.podIPs.'
properties:
apiVersion:
description: Version of the schema the
FieldPath is written in terms of,
defaults to "v1".
type: string
fieldPath:
description: Path of the field to select
in the specified API version.
type: string
required:
- fieldPath
type: object
x-kubernetes-map-type: atomic
resourceFieldRef:
description: 'Selects a resource of the
container: only resources limits and requests
(limits.cpu, limits.memory, limits.ephemeral-storage,
requests.cpu, requests.memory and requests.ephemeral-storage)
are currently supported.'
properties:
containerName:
description: 'Container name: required
for volumes, optional for env vars'
type: string
divisor:
anyOf:
- type: integer
- type: string
description: Specifies the output format
of the exposed resources, defaults
to "1"
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
x-kubernetes-int-or-string: true
resource:
description: 'Required: resource to
select'
type: string
required:
- resource
type: object
x-kubernetes-map-type: atomic
secretKeyRef:
description: Selects a key of a secret in
the pod's namespace
properties:
key:
description: The key of the secret to
select from. Must be a valid secret
key.
type: string
name:
description: 'Name of the referent.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Add other useful fields. apiVersion,
kind, uid?'
type: string
optional:
description: Specify whether the Secret
or its key must be defined
type: boolean
required:
- key
type: object
x-kubernetes-map-type: atomic
type: object
required:
- name
type: object
type: array
image:
description: Image specifies the EnvoyProxy container
image to be used, instead of the default image.
Expand Down
1 change: 1 addition & 0 deletions docs/latest/api/config_types.md
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,7 @@ _Appears in:_

| Field | Description |
| --- | --- |
| `env` _[EnvVar](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.26/#envvar-v1-core) array_ | List of environment variables to set in the container. |
| `resources` _[ResourceRequirements](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.26/#resourcerequirements-v1-core)_ | Resources required by this container. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ |
| `securityContext` _[SecurityContext](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.26/#securitycontext-v1-core)_ | SecurityContext defines the security options the container should be run with. If set, the fields of SecurityContext override the equivalent fields of PodSecurityContext. More info: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ |
| `image` _string_ | Image specifies the EnvoyProxy container image to be used, instead of the default image. |
Expand Down
10 changes: 10 additions & 0 deletions internal/envoygateway/config/decoder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,16 @@ func TestDecode(t *testing.T) {
RateLimitDeployment: &v1alpha1.KubernetesDeploymentSpec{
Replicas: v1alpha1.DefaultKubernetesDeploymentReplicas(),
Container: &v1alpha1.KubernetesContainerSpec{
Env: []corev1.EnvVar{
{
Name: "env_a",
Value: "env_a_value",
},
{
Name: "env_b",
Value: "env_b_value",
},
},
Image: pointer.String("envoyproxy/ratelimit:latest"),
Resources: v1alpha1.DefaultResourceRequirements(),
SecurityContext: &corev1.SecurityContext{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ provider:
rateLimitDeployment:
replicas: 1
container:
env:
- name: env_a
value: env_a_value
- name: env_b
value: env_b_value
image: envoyproxy/ratelimit:latest
resources:
requests:
Expand Down
5 changes: 5 additions & 0 deletions internal/gatewayapi/testdata/envoyproxy-valid.in.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ envoyproxy:
envoyDeployment:
replicas: 2
container:
env:
- name: env_a
value: env_a_value
- name: env_b
value: env_b_name
image: "envoyproxy/gateway:v0.4.0"
resources:
requests:
Expand Down
5 changes: 5 additions & 0 deletions internal/gatewayapi/testdata/envoyproxy-valid.out.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,11 @@ infraIR:
envoyDeployment:
replicas: 2
container:
env:
- name: env_a
value: env_a_value
- name: env_b
value: env_b_name
image: "envoyproxy/gateway:v0.4.0"
resources:
requests:
Expand Down
119 changes: 119 additions & 0 deletions internal/infrastructure/kubernetes/proxy/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,13 @@ package proxy
import (
"fmt"

corev1 "k8s.io/api/core/v1"

egcfgv1a1 "github.com/envoyproxy/gateway/api/config/v1alpha1"
"github.com/envoyproxy/gateway/internal/envoygateway/config"
"github.com/envoyproxy/gateway/internal/ir"
providerutils "github.com/envoyproxy/gateway/internal/provider/utils"
"github.com/envoyproxy/gateway/internal/xds/bootstrap"
)

const (
Expand All @@ -24,6 +29,12 @@ const (
// XdsTLSCaFilename is the fully qualified path of the file containing Envoy's
// trusted CA certificate.
XdsTLSCaFilename = "/certs/ca.crt"
// envoyContainerName is the name of the Envoy container.
envoyContainerName = "envoy"
// envoyNsEnvVar is the name of the Envoy Gateway namespace environment variable.
envoyNsEnvVar = "ENVOY_GATEWAY_NAMESPACE"
// envoyPodEnvVar is the name of the Envoy pod name environment variable.
envoyPodEnvVar = "ENVOY_POD_NAME"
)

var (
Expand Down Expand Up @@ -58,3 +69,111 @@ func envoyLabels(extraLabels map[string]string) map[string]string {

return labels
}

// expectedProxyContainers returns expected proxy containers.
func expectedProxyContainers(infra *ir.ProxyInfra, deploymentConfig *egcfgv1a1.KubernetesDeploymentSpec) ([]corev1.Container, error) {
// Define slice to hold container ports
var ports []corev1.ContainerPort

// Iterate over listeners and ports to get container ports
for _, listener := range infra.Listeners {
for _, p := range listener.Ports {
var protocol corev1.Protocol
switch p.Protocol {
case ir.HTTPProtocolType, ir.HTTPSProtocolType, ir.TLSProtocolType, ir.TCPProtocolType:
protocol = corev1.ProtocolTCP
case ir.UDPProtocolType:
protocol = corev1.ProtocolUDP
default:
return nil, fmt.Errorf("invalid protocol %q", p.Protocol)
}
port := corev1.ContainerPort{
Name: p.Name,
ContainerPort: p.ContainerPort,
Protocol: protocol,
}
ports = append(ports, port)
}
}

var bootstrapConfigurations string
// Get Bootstrap from EnvoyProxy API if set by the user
// The config should have been validated already
if infra.Config != nil &&
infra.Config.Spec.Bootstrap != nil {
bootstrapConfigurations = *infra.Config.Spec.Bootstrap
} else {
var err error
// Use the default Bootstrap
bootstrapConfigurations, err = bootstrap.GetRenderedBootstrapConfig()
if err != nil {
return nil, err
}
}

containers := []corev1.Container{
{
Name: envoyContainerName,
Image: *deploymentConfig.Container.Image,
ImagePullPolicy: corev1.PullIfNotPresent,
Command: []string{
"envoy",
},
Args: []string{
fmt.Sprintf("--service-cluster %s", infra.Name),
fmt.Sprintf("--service-node $(%s)", envoyPodEnvVar),
fmt.Sprintf("--config-yaml %s", bootstrapConfigurations),
"--log-level info",
},
Env: expectedProxyContainerEnv(deploymentConfig),
Resources: *deploymentConfig.Container.Resources,
SecurityContext: deploymentConfig.Container.SecurityContext,
Ports: ports,
VolumeMounts: []corev1.VolumeMount{
{
Name: "certs",
MountPath: "/certs",
ReadOnly: true,
},
{
Name: "sds",
MountPath: "/sds",
},
},
TerminationMessagePolicy: corev1.TerminationMessageReadFile,
TerminationMessagePath: "/dev/termination-log",
},
}

return containers, nil
}

// expectedProxyContainerEnv returns expected proxy container envs.
func expectedProxyContainerEnv(deploymentConfig *egcfgv1a1.KubernetesDeploymentSpec) []corev1.EnvVar {
env := []corev1.EnvVar{
{
Name: envoyNsEnvVar,
ValueFrom: &corev1.EnvVarSource{
FieldRef: &corev1.ObjectFieldSelector{
APIVersion: "v1",
FieldPath: "metadata.namespace",
},
},
},
{
Name: envoyPodEnvVar,
ValueFrom: &corev1.EnvVarSource{
FieldRef: &corev1.ObjectFieldSelector{
APIVersion: "v1",
FieldPath: "metadata.name",
},
},
},
}

if extensionEnv := deploymentConfig.Container.Env; extensionEnv != nil {
env = append(env, extensionEnv...)
}

return env
}
Loading