From a66de4c601bf9fc3b6dffbd86965a9362ccf7f61 Mon Sep 17 00:00:00 2001 From: Ta-Ching Chen Date: Fri, 22 Nov 2019 18:19:57 +0800 Subject: [PATCH] Support to set imagePullSecret when creating environment (#1429) --- pkg/apis/fission.io/v1/types.go | 4 +++ pkg/executor/newdeploy/newdeploy.go | 36 ++++++++++++-------- pkg/executor/newdeploy/newdeploymgr.go | 12 +++---- pkg/executor/poolmgr/gp.go | 36 ++++++++++++-------- pkg/executor/util/util.go | 38 ++++++++++++++++++++++ pkg/fission-cli/cmd/environment/command.go | 8 ++--- pkg/fission-cli/cmd/environment/create.go | 2 ++ pkg/fission-cli/cmd/environment/update.go | 4 +++ pkg/fission-cli/flag/flag.go | 1 + pkg/fission-cli/flag/key/key.go | 1 + 10 files changed, 104 insertions(+), 38 deletions(-) create mode 100644 pkg/executor/util/util.go diff --git a/pkg/apis/fission.io/v1/types.go b/pkg/apis/fission.io/v1/types.go index 72830b2e..45b8b9d5 100644 --- a/pkg/apis/fission.io/v1/types.go +++ b/pkg/apis/fission.io/v1/types.go @@ -528,6 +528,10 @@ type ( // or unarchived file should be placed, which is then used by specialize handler. // (This is mainly for the JVM environment because .jar is one kind of zip archive.) KeepArchive bool `json:"keeparchive"` + + // ImagePullSecret is the secret for Kubernetes to pull an image from a + // private registry. + ImagePullSecret string `json:"imagepullsecret"` } AllowedFunctionsPerContainer string diff --git a/pkg/executor/newdeploy/newdeploy.go b/pkg/executor/newdeploy/newdeploy.go index 3ed22927..de7a42d0 100644 --- a/pkg/executor/newdeploy/newdeploy.go +++ b/pkg/executor/newdeploy/newdeploy.go @@ -17,11 +17,11 @@ limitations under the License. package newdeploy import ( - "errors" "fmt" "time" multierror "github.com/hashicorp/go-multierror" + "github.com/pkg/errors" "go.uber.org/zap" appsv1 "k8s.io/api/apps/v1" asv1 "k8s.io/api/autoscaling/v1" @@ -76,7 +76,7 @@ func (deploy *NewDeploy) createOrGetDeployment(fn *fv1.Function, env *fv1.Enviro return nil, err } - deployment, err := deploy.getDeploymentSpec(fn, env, deployName, deployLabels) + deployment, err := deploy.getDeploymentSpec(fn, env, deployName, deployNamespace, deployLabels) if err != nil { return nil, err } @@ -158,7 +158,7 @@ func (deploy *NewDeploy) deleteDeployment(ns string, name string) error { } func (deploy *NewDeploy) getDeploymentSpec(fn *fv1.Function, env *fv1.Environment, - deployName string, deployLabels map[string]string) (*appsv1.Deployment, error) { + deployName string, deployNamespace string, deployLabels map[string]string) (*appsv1.Deployment, error) { replicas := int32(fn.Spec.InvokeStrategy.ExecutionStrategy.MinScale) @@ -227,6 +227,24 @@ func (deploy *NewDeploy) getDeploymentSpec(fn *fv1.Function, env *fv1.Environmen return nil, err } + pod := apiv1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Labels: deployLabels, + Annotations: podAnnotations, + }, + Spec: apiv1.PodSpec{ + Containers: []apiv1.Container{*container}, + ServiceAccountName: "fission-fetcher", + TerminationGracePeriodSeconds: &gracePeriodSeconds, + }, + } + + podspec, err := util.ApplyImagePullSecret(deploy.kubernetesClient, env.Spec.ImagePullSecret, deployNamespace, pod.Spec) + if err != nil { + return nil, errors.Wrapf(err, "failed to apply image pull secret for env '%v'", env.Metadata.Name) + } + pod.Spec = *podspec + deployment := &appsv1.Deployment{ ObjectMeta: metav1.ObjectMeta{ Name: deployName, @@ -237,17 +255,7 @@ func (deploy *NewDeploy) getDeploymentSpec(fn *fv1.Function, env *fv1.Environmen Selector: &metav1.LabelSelector{ MatchLabels: deployLabels, }, - Template: apiv1.PodTemplateSpec{ - ObjectMeta: metav1.ObjectMeta{ - Labels: deployLabels, - Annotations: podAnnotations, - }, - Spec: apiv1.PodSpec{ - Containers: []apiv1.Container{*container}, - ServiceAccountName: "fission-fetcher", - TerminationGracePeriodSeconds: &gracePeriodSeconds, - }, - }, + Template: pod, Strategy: appsv1.DeploymentStrategy{ Type: appsv1.RollingUpdateDeploymentStrategyType, RollingUpdate: &appsv1.RollingUpdateDeployment{ diff --git a/pkg/executor/newdeploy/newdeploymgr.go b/pkg/executor/newdeploy/newdeploymgr.go index eedc9a2f..e00c01dd 100644 --- a/pkg/executor/newdeploy/newdeploymgr.go +++ b/pkg/executor/newdeploy/newdeploymgr.go @@ -535,12 +535,6 @@ func (deploy *NewDeploy) updateFuncDeployment(fn *fv1.Function, env *fv1.Environ deploy.logger.Info("updating deployment due to function/environment update", zap.String("deployment", fnObjName), zap.Any("function", fn.Metadata.Name)) - newDeployment, err := deploy.getDeploymentSpec(fn, env, fnObjName, deployLabels) - if err != nil { - deploy.updateStatus(fn, err, "failed to get new deployment spec while updating function") - return err - } - // to support backward compatibility, if the function was created in default ns, we fall back to creating the // deployment of the function in fission-function ns ns := deploy.namespace @@ -548,6 +542,12 @@ func (deploy *NewDeploy) updateFuncDeployment(fn *fv1.Function, env *fv1.Environ ns = fn.Metadata.Namespace } + newDeployment, err := deploy.getDeploymentSpec(fn, env, fnObjName, ns, deployLabels) + if err != nil { + deploy.updateStatus(fn, err, "failed to get new deployment spec while updating function") + return err + } + err = deploy.updateDeployment(newDeployment, ns) if err != nil { deploy.updateStatus(fn, err, "failed to update deployment while updating function") diff --git a/pkg/executor/poolmgr/gp.go b/pkg/executor/poolmgr/gp.go index b4d64546..5e0a7f22 100644 --- a/pkg/executor/poolmgr/gp.go +++ b/pkg/executor/poolmgr/gp.go @@ -389,6 +389,27 @@ func (gp *GenericPool) createPool() error { return err } + pod := apiv1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Labels: gp.labelsForPool, + Annotations: podAnnotations, + }, + Spec: apiv1.PodSpec{ + Containers: []apiv1.Container{*container}, + ServiceAccountName: "fission-fetcher", + // TerminationGracePeriodSeconds should be equal to the + // sleep time of preStop to make sure that SIGTERM is sent + // to pod after 6 mins. + TerminationGracePeriodSeconds: &gracePeriodSeconds, + }, + } + + podspec, err := util.ApplyImagePullSecret(gp.kubernetesClient, gp.env.Spec.ImagePullSecret, gp.namespace, pod.Spec) + if err != nil { + return errors.Wrapf(err, "failed to apply image pull secret for env '%v'", gp.env.Metadata.Name) + } + pod.Spec = *podspec + deployment := &appsv1.Deployment{ ObjectMeta: metav1.ObjectMeta{ Name: gp.getPoolName(), @@ -399,20 +420,7 @@ func (gp *GenericPool) createPool() error { Selector: &metav1.LabelSelector{ MatchLabels: gp.labelsForPool, }, - Template: apiv1.PodTemplateSpec{ - ObjectMeta: metav1.ObjectMeta{ - Labels: gp.labelsForPool, - Annotations: podAnnotations, - }, - Spec: apiv1.PodSpec{ - Containers: []apiv1.Container{*container}, - ServiceAccountName: "fission-fetcher", - // TerminationGracePeriodSeconds should be equal to the - // sleep time of preStop to make sure that SIGTERM is sent - // to pod after 6 mins. - TerminationGracePeriodSeconds: &gracePeriodSeconds, - }, - }, + Template: pod, }, } diff --git a/pkg/executor/util/util.go b/pkg/executor/util/util.go new file mode 100644 index 00000000..418d3973 --- /dev/null +++ b/pkg/executor/util/util.go @@ -0,0 +1,38 @@ +/* +Copyright 2019 The Fission Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package util + +import ( + "github.com/pkg/errors" + apiv1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes" +) + +// ApplyImagePullSecret applies image pull secret to the give pod spec. An error will be returned if failed to get secret. +func ApplyImagePullSecret(client *kubernetes.Clientset, secret string, secretNS string, podspec apiv1.PodSpec) (*apiv1.PodSpec, error) { + if len(secret) > 0 && client != nil { + _, err := client.CoreV1().Secrets(secretNS).Get(secret, metav1.GetOptions{}) + if err != nil { + err = errors.Wrapf(err, "unable to get image pull secret '%v' under namespace '%v'", + secret, secretNS) + return nil, err + } + podspec.ImagePullSecrets = []apiv1.LocalObjectReference{{Name: secret}} + } + return &podspec, nil +} diff --git a/pkg/fission-cli/cmd/environment/command.go b/pkg/fission-cli/cmd/environment/command.go index 862cc7b0..9703405f 100644 --- a/pkg/fission-cli/cmd/environment/command.go +++ b/pkg/fission-cli/cmd/environment/command.go @@ -33,8 +33,8 @@ func Commands() *cobra.Command { Required: []flag.Flag{flag.EnvName, flag.EnvImage}, Optional: []flag.Flag{flag.EnvPoolsize, flag.EnvBuilderImage, flag.EnvBuildCmd, flag.RunTimeMinCPU, flag.RunTimeMaxCPU, flag.RunTimeMinMemory, flag.RunTimeMaxMemory, - flag.EnvTerminationGracePeriod, flag.EnvVersion, flag.EnvExternalNetwork, flag.EnvKeepArchive, - flag.NamespaceEnvironment, flag.SpecSave}, + flag.EnvTerminationGracePeriod, flag.EnvVersion, flag.EnvImagePullSecret, + flag.EnvExternalNetwork, flag.EnvKeepArchive, flag.NamespaceEnvironment, flag.SpecSave}, }) getCmd := &cobra.Command{ @@ -55,8 +55,8 @@ func Commands() *cobra.Command { wrapper.SetFlags(updateCmd, flag.FlagSet{ Required: []flag.Flag{flag.EnvName}, Optional: []flag.Flag{flag.EnvImage, flag.EnvPoolsize, - flag.EnvBuilderImage, flag.EnvBuildCmd, flag.EnvExternalNetwork, - flag.EnvTerminationGracePeriod, flag.EnvKeepArchive, flag.NamespaceEnvironment}, + flag.EnvBuilderImage, flag.EnvBuildCmd, flag.EnvImagePullSecret, flag.EnvTerminationGracePeriod, + flag.EnvKeepArchive, flag.NamespaceEnvironment, flag.EnvExternalNetwork}, }) deleteCmd := &cobra.Command{ diff --git a/pkg/fission-cli/cmd/environment/create.go b/pkg/fission-cli/cmd/environment/create.go index 47e73e9d..e4aeff21 100644 --- a/pkg/fission-cli/cmd/environment/create.go +++ b/pkg/fission-cli/cmd/environment/create.go @@ -112,6 +112,7 @@ func createEnvironmentFromCmd(input cli.Input) (*fv1.Environment, error) { envExternalNetwork := input.Bool(flagkey.EnvExternalNetwork) keepArchive := input.Bool(flagkey.EnvKeeparchive) envGracePeriod := input.Int64(flagkey.EnvGracePeriod) + pullSecret := input.String(flagkey.EnvImagePullSecret) envVersion := input.Int(flagkey.EnvVersion) // Environment API interface version is not specified and @@ -169,6 +170,7 @@ func createEnvironmentFromCmd(input cli.Input) (*fv1.Environment, error) { AllowAccessToExternalNetwork: envExternalNetwork, TerminationGracePeriod: envGracePeriod, KeepArchive: keepArchive, + ImagePullSecret: pullSecret, }, } diff --git a/pkg/fission-cli/cmd/environment/update.go b/pkg/fission-cli/cmd/environment/update.go index ea394049..af9b9756 100644 --- a/pkg/fission-cli/cmd/environment/update.go +++ b/pkg/fission-cli/cmd/environment/update.go @@ -123,6 +123,10 @@ func updateExistingEnvironmentWithCmd(env *fv1.Environment, input cli.Input) (*f env.Spec.KeepArchive = input.Bool(flagkey.EnvKeeparchive) } + if input.IsSet(flagkey.EnvImagePullSecret) { + env.Spec.ImagePullSecret = input.String(flagkey.EnvImagePullSecret) + } + env.Spec.AllowAccessToExternalNetwork = envExternalNetwork // TODO: allow to update resource. diff --git a/pkg/fission-cli/flag/flag.go b/pkg/fission-cli/flag/flag.go index 475d2139..5f20d6ab 100644 --- a/pkg/fission-cli/flag/flag.go +++ b/pkg/fission-cli/flag/flag.go @@ -142,6 +142,7 @@ var ( EnvExternalNetwork = Flag{Type: Bool, Name: flagkey.EnvExternalNetwork, Usage: "Allow pod to access external network (only works when istio feature is enabled)"} EnvTerminationGracePeriod = Flag{Type: Int, Name: flagkey.EnvGracePeriod, Aliases: []string{"period"}, Usage: "Grace time (in seconds) for pod to perform connection draining before termination", DefaultValue: 360} EnvVersion = Flag{Type: Int, Name: flagkey.EnvVersion, Usage: "Environment API version (1 means v1 interface)", DefaultValue: 1} + EnvImagePullSecret = Flag{Type: String, Name: flagkey.EnvImagePullSecret, Usage: "Secret for Kubernetes to pull an image from a private registry"} KwName = Flag{Type: String, Name: flagkey.KwName, Usage: "Watch name"} KwFnName = Flag{Type: String, Name: flagkey.KwFnName, Usage: "Function name"} diff --git a/pkg/fission-cli/flag/key/key.go b/pkg/fission-cli/flag/key/key.go index 36eb65fc..a74969b6 100644 --- a/pkg/fission-cli/flag/key/key.go +++ b/pkg/fission-cli/flag/key/key.go @@ -96,6 +96,7 @@ const ( EnvExternalNetwork = "externalnetwork" EnvGracePeriod = "graceperiod" EnvVersion = "version" + EnvImagePullSecret = "imagepullsecret" KwName = resourceName KwFnName = "function"