Skip to content
This repository was archived by the owner on Nov 16, 2020. It is now read-only.

Commit f552804

Browse files
authored
Adding support for private registries (image pull) (#438)
* Previously functions could not pull private images * Also fix single-namespace install - transports now install correctly * Only supports OpenFaaS - Riff does not support image pull secrets Needs e2e tests. Tested manually on minikube
1 parent 8ce1410 commit f552804

File tree

10 files changed

+91
-4
lines changed

10 files changed

+91
-4
lines changed

charts/dispatch/charts/function-manager/templates/config-map.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ data:
1919
"gateway": "{{ .Values.faas.openfaas.gateway }}",
2020
"funcNamespace": "{{ .Values.faas.openfaas.namespace }}",
2121
"funcDefaultLimits": {{ toJson .Values.faas.openfaas.funcDefaultLimits }},
22-
"funcDefaultRequests": {{ toJson .Values.faas.openfaas.funcDefaultRequests }}
22+
"funcDefaultRequests": {{ toJson .Values.faas.openfaas.funcDefaultRequests }},
23+
"imagePullSecret": "{{ .Values.faas.openfaas.imagePullSecret }}"
2324
},
2425
"riff": {
2526
"kafkaBrokers": ["{{ join ", " .Values.global.kafka.brokers }}"],

charts/dispatch/charts/function-manager/values.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ faas:
4646
openfaas:
4747
gateway: "http://gateway.openfaas:8080/"
4848
namespace: openfaas
49+
imagePullSecret:
4950
# Set the default resource limits for the function containers
5051
funcDefaultLimits:
5152
# CPU: 500m

charts/openfaas/templates/rbac.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,14 @@ rules:
3434
- create
3535
- delete
3636
- update
37+
- apiGroups:
38+
- ""
39+
resources:
40+
- secrets
41+
verbs:
42+
- get
43+
- list
44+
- watch
3745
---
3846
apiVersion: rbac.authorization.k8s.io/v1beta1
3947
kind: ClusterRoleBinding

cmd/function-manager/main.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ var drivers = map[string]func(string) functions.FaaSDriver{
4545
FuncNamespace: config.Global.Function.OpenFaas.FuncNamespace,
4646
FuncDefaultRequests: config.Global.Function.OpenFaas.FuncDefaultRequests,
4747
FuncDefaultLimits: config.Global.Function.OpenFaas.FuncDefaultLimits,
48+
ImagePullSecret: config.Global.Function.OpenFaas.ImagePullSecret,
4849
})
4950
if err != nil {
5051
log.Fatalf("Error starting OpenFaaS driver: %+v", err)

docs/_guides/advanced.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,25 @@ Docker hub example:
146146
$ kubectl create secret docker-registry regsecret --docker-server='https://index.docker.io/v1/' --docker-username=dockerhub-user --docker-password='...' --docker-email=dockerhub-user@gmail.com
147147
```
148148

149+
### Image Pull Secrets
150+
151+
Depending on the image registry, secrets may be required to pull images. **Only OpenFaaS supports image
152+
pull secrets**. To configure image pull secrets simply configure installation:
153+
154+
```yaml
155+
apiGateway:
156+
...
157+
dispatch:
158+
...
159+
imagePullSecret: pull-secret
160+
imageRegistry:
161+
name: some-repo.example.com
162+
username: username
163+
password: password
164+
```
165+
166+
The installer will take care of creating a secret and associating it to OpenFaaS.
167+
149168
## Import self-signed TLS certificates into Kubernetes secret
150169
151170
To be able to securely connect to Dispatch, we need to set up a TLS certificate.

pkg/config/config.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ type OpenFaas struct {
4646
Gateway string `json:"gateway"`
4747
K8sConfig string `json:"k8sConfig"`
4848
FuncNamespace string `json:"funcNamespace"`
49+
ImagePullSecret string `json:"imagePullSecret"`
4950
FuncDefaultLimits *FunctionResources `json:"funcDefaultLimits"`
5051
FuncDefaultRequests *FunctionResources `json:"funcDefaultRequests"`
5152
}

pkg/dispatchcli/cmd/install.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ type dispatchInstallConfig struct {
160160
Database string `json:"database,omitempty" validate:"required,eq=postgres"`
161161
PersistData bool `json:"persistData,omitempty" validate:"omitempty"`
162162
ImageRegistry *imageRegistryConfig `json:"imageRegistry,omitempty" validate:"omitempty"`
163+
ImagePullSecret string `json:"imagePullSecret,omitempty" validate:"omitempty"`
163164
OAuth2Proxy *oauth2ProxyConfig `json:"oauth2Proxy,omitempty" validate:"required"`
164165
TLS *tlsConfig `json:"tls,omitempty" validate:"required"`
165166
SkipAuth bool `json:"skipAuth,omitempty" validate:"omitempty"`
@@ -673,6 +674,9 @@ func runInstall(out, errOut io.Writer, cmd *cobra.Command, args []string) error
673674
config.Ingress.Chart.Namespace = installSingleNS
674675
config.DockerRegistry.Chart.Namespace = installSingleNS
675676
config.DispatchConfig.Service.K8sServiceCatalog.Namespace = installSingleNS
677+
config.RabbitMQ.Chart.Namespace = installSingleNS
678+
config.Kafka.Chart.Namespace = installSingleNS
679+
config.Kafka.Brokers = []string{fmt.Sprintf("transport-kafka.%s:9092", installSingleNS)}
676680
}
677681

678682
if installService("certs") || !installDryRun {
@@ -846,6 +850,45 @@ func runInstall(out, errOut io.Writer, cmd *cobra.Command, args []string) error
846850
}
847851
}
848852

853+
if config.DispatchConfig.ImagePullSecret != "" {
854+
if config.DispatchConfig.Faas != "openfaas" {
855+
return errors.Errorf(
856+
"Must use openfaas with private registries %s is unsupported", config.DispatchConfig.Faas)
857+
}
858+
// the installed openfaas version expects the "dockercfg" credential format, but the current
859+
// kubectl (>1.9.1) creates "dockerconfigjson" credentials which openfaas doesn't like. This
860+
// has been fixed in recent openfaas, and then the following code will go away.
861+
auth := fmt.Sprintf(
862+
"%s:%s", config.DispatchConfig.ImageRegistry.Username, config.DispatchConfig.ImageRegistry.Password)
863+
dockercfg := map[string]map[string]string{
864+
config.DispatchConfig.ImageRegistry.Name: map[string]string{
865+
"username": config.DispatchConfig.ImageRegistry.Username,
866+
"password": config.DispatchConfig.ImageRegistry.Password,
867+
"email": config.DispatchConfig.ImageRegistry.Email,
868+
"auth": base64.StdEncoding.EncodeToString([]byte(auth)),
869+
},
870+
}
871+
cfg, _ := json.Marshal(dockercfg)
872+
kubectl := exec.Command(
873+
"kubectl", "delete", "secret", config.DispatchConfig.ImagePullSecret,
874+
"-n", config.OpenFaas.Chart.Namespace)
875+
kubectlOut, err := kubectl.CombinedOutput()
876+
if err != nil {
877+
if !strings.Contains(string(kubectlOut), "NotFound") {
878+
return errors.Wrapf(err, "failed to delete existing image pull secret: %s", kubectlOut)
879+
}
880+
}
881+
kubectl = exec.Command(
882+
"kubectl", "create", "secret", "generic", config.DispatchConfig.ImagePullSecret,
883+
"-n", config.OpenFaas.Chart.Namespace,
884+
"--type", "kubernetes.io/dockercfg",
885+
"--from-literal", fmt.Sprintf(".dockercfg=%s", cfg))
886+
kubectlOut, err = kubectl.CombinedOutput()
887+
if err != nil {
888+
return errors.Wrapf(err, "failed to create image pull secret: %s", kubectlOut)
889+
}
890+
}
891+
849892
if installService("dispatch") {
850893
chart := path.Join(installChartsDir, "dispatch")
851894
if installChartsDir != "dispatch" {
@@ -934,6 +977,7 @@ func runInstall(out, errOut io.Writer, cmd *cobra.Command, args []string) error
934977
"function-manager.faas.selected": config.DispatchConfig.Faas,
935978
"function-manager.faas.openfaas.gateway": openfaasGatewayHost,
936979
"function-manager.faas.openfaas.namespace": config.OpenFaas.Chart.Namespace,
980+
"function-manager.faas.openfaas.imagePullSecret": config.DispatchConfig.ImagePullSecret,
937981
"function-manager.faas.riff.gateway": riffGatewayHost,
938982
"function-manager.faas.riff.namespace": config.Riff.Chart.Namespace,
939983
"event-manager.transport": config.DispatchConfig.EventTransport,

pkg/dispatchcli/cmd/install_config.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ dispatch:
127127
# username:
128128
# email:
129129
# password:
130+
imagePullSecret:
130131
service:
131132
catalog: k8sservicecatalog
132133
k8sservicecatalog:

pkg/functions/builder.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,11 @@ func (ib *DockerImageBuilder) BuildImage(faas, fnID string, exec *Exec) (string,
8484
defer os.RemoveAll(tmpDir)
8585

8686
log.Debugf("Created tmpDir: %s", tmpDir)
87-
88-
if err := images.DockerError(ib.docker.ImagePull(context.Background(), exec.Image, types.ImagePullOptions{})); err != nil {
87+
opts := types.ImagePullOptions{}
88+
if ib.registryAuth != "" {
89+
opts.RegistryAuth = ib.registryAuth
90+
}
91+
if err := images.DockerError(ib.docker.ImagePull(context.Background(), exec.Image, opts)); err != nil {
8992
return "", errors.Wrapf(err, "failed to pull image '%s'", exec.Image)
9093
}
9194

pkg/functions/openfaas/driver.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ type Config struct {
4848
FuncDefaultLimits *config.FunctionResources
4949
FuncDefaultRequests *config.FunctionResources
5050
CreateTimeout *int
51+
ImagePullSecret string
5152
}
5253

5354
type ofDriver struct {
@@ -59,7 +60,8 @@ type ofDriver struct {
5960

6061
deployments v1beta1.DeploymentInterface
6162

62-
createTimeout int
63+
createTimeout int
64+
imagePullSecret string
6365

6466
funcDefaultLimits *requests.FunctionResources
6567
funcDefaultRequests *requests.FunctionResources
@@ -114,6 +116,9 @@ func New(config *Config) (functions.FaaSDriver, error) {
114116
if config.CreateTimeout != nil {
115117
d.createTimeout = *config.CreateTimeout
116118
}
119+
if config.ImagePullSecret != "" {
120+
d.imagePullSecret = config.ImagePullSecret
121+
}
117122

118123
return d, nil
119124
}
@@ -143,6 +148,9 @@ func (d *ofDriver) Create(f *functions.Function, exec *functions.Exec) error {
143148
Limits: d.funcDefaultLimits,
144149
Requests: d.funcDefaultRequests,
145150
}
151+
if d.imagePullSecret != "" {
152+
req.Secrets = []string{d.imagePullSecret}
153+
}
146154

147155
reqBytes, _ := json.Marshal(&req)
148156
res, err := d.httpClient.Post(d.gateway+"/system/functions", jsonContentType, bytes.NewReader(reqBytes))

0 commit comments

Comments
 (0)