Merge pull request #42548 from andrewrynhard/use_secrets

Automatic merge from submit-queue (batch tested with PRs 48374, 48524, 48519, 42548, 48615)

Use Secrets for files that self-hosted pods depend on

**What this PR does / why we need it**:
See https://github.com/kubernetes/kubeadm/issues/194

**Release note**:

```release-note
NONE
```

```
bash-4.2# kubectl --kubeconfig /etc/kubernetes/admin.conf get pods -n kube-system
NAME                                                   READY     STATUS    RESTARTS   AGE
dummy-1628042694-6ghbq                                 1/1       Running   0          42m
kube-dns-1853130399-4nzx4                              3/3       Running   0          9m
kube-flannel-ds-mnq10                                  2/2       Running   2          12m
kube-flannel-ds-n3tl8                                  2/2       Running   0          42m
kube-proxy-lqpcb                                       1/1       Running   0          42m
kube-proxy-pw0pw                                       1/1       Running   0          12m
self-hosted-kube-apiserver-fkkwd                       1/1       Running   1          42m
self-hosted-kube-controller-manager-1387498942-mzg41   1/1       Running   1          42m
self-hosted-kube-scheduler-2588609441-cwhqb            1/1       Running   1          42m
```

### API Server
```
bash-4.2# kubectl --kubeconfig /etc/kubernetes/admin.conf exec self-hosted-kube-apiserver-fkkwd -n kube-system -- ls /etc/pki
ca-trust
java
nssdb
rpm-gpg
tls
bash-4.2# kubectl --kubeconfig /etc/kubernetes/admin.conf exec self-hosted-kube-apiserver-fkkwd -n kube-system -- ls /etc/ssl
certs
bash-4.2# kubectl --kubeconfig /etc/kubernetes/admin.conf exec self-hosted-kube-apiserver-fkkwd -n kube-system -- ls /etc/kubernetes/
pki
bash-4.2# kubectl --kubeconfig /etc/kubernetes/admin.conf exec self-hosted-kube-apiserver-fkkwd -n kube-system -- ls /etc/kubernetes/pki/
apiserver-kubelet-client.crt
apiserver-kubelet-client.key
apiserver.crt
apiserver.key
ca.crt
front-proxy-ca.crt
sa.pub
```

### Scheduler
```
bash-4.2# kubectl --kubeconfig /etc/kubernetes/admin.conf exec self-hosted-kube-scheduler-2588609441-cwhqb -n kube-system -- ls /etc/kubernetes/
scheduler.conf
```

### Controller Manager
```
bash-4.2# kubectl --kubeconfig /etc/kubernetes/admin.conf exec self-hosted-kube-controller-manager-1387498942-mzg41 -n kube-system -- ls /etc/ssl
certs
bash-4.2# kubectl --kubeconfig /etc/kubernetes/admin.conf exec self-hosted-kube-controller-manager-1387498942-mzg41 -n kube-system -- ls /etc/pki
ca-trust
java
nssdb
rpm-gpg
tls
bash-4.2# kubectl --kubeconfig /etc/kubernetes/admin.conf exec self-hosted-kube-controller-manager-1387498942-mzg41 -n kube-system -- ls /etc/kubernetes/
controller-manager.conf
pki
bash-4.2# kubectl --kubeconfig /etc/kubernetes/admin.conf exec self-hosted-kube-controller-manager-1387498942-mzg41 -n kube-system -- ls /etc/kubernetes/pki/
ca.crt
ca.key
sa.key
```

/cc @luxas @liggitt @pires @timothysc
pull/6/head
Kubernetes Submit Queue 2017-07-07 14:48:33 -07:00 committed by GitHub
commit 89136f64b9
9 changed files with 622 additions and 35 deletions

View File

@ -271,7 +271,7 @@ func (i *Init) Run(out io.Writer) error {
// Temporary control plane is up, now we create our self hosted control // Temporary control plane is up, now we create our self hosted control
// plane components and remove the static manifests: // plane components and remove the static manifests:
fmt.Println("[self-hosted] Creating self-hosted control plane...") fmt.Println("[self-hosted] Creating self-hosted control plane...")
if err := selfhostingphase.CreateSelfHostedControlPlane(client); err != nil { if err := selfhostingphase.CreateSelfHostedControlPlane(i.cfg, client); err != nil {
return err return err
} }
} }

View File

@ -19,23 +19,30 @@ package phases
import ( import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
kubeadmapiext "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha1"
"k8s.io/kubernetes/cmd/kubeadm/app/phases/selfhosting" "k8s.io/kubernetes/cmd/kubeadm/app/phases/selfhosting"
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util" kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
kubeconfigutil "k8s.io/kubernetes/cmd/kubeadm/app/util/kubeconfig" kubeconfigutil "k8s.io/kubernetes/cmd/kubeadm/app/util/kubeconfig"
"k8s.io/kubernetes/pkg/api"
) )
// NewCmdSelfhosting returns the self-hosting Cobra command // NewCmdSelfhosting returns the self-hosting Cobra command
func NewCmdSelfhosting() *cobra.Command { func NewCmdSelfhosting() *cobra.Command {
var kubeConfigFile string var kubeConfigFile string
cfg := &kubeadmapiext.MasterConfiguration{}
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "selfhosting", Use: "selfhosting",
Aliases: []string{"selfhosted"}, Aliases: []string{"selfhosted"},
Short: "Make a kubeadm cluster self-hosted.", Short: "Make a kubeadm cluster self-hosted.",
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
api.Scheme.Default(cfg)
internalcfg := &kubeadmapi.MasterConfiguration{}
api.Scheme.Convert(cfg, internalcfg, nil)
client, err := kubeconfigutil.ClientSetFromFile(kubeConfigFile) client, err := kubeconfigutil.ClientSetFromFile(kubeConfigFile)
kubeadmutil.CheckErr(err) kubeadmutil.CheckErr(err)
err = selfhosting.CreateSelfHostedControlPlane(client) err = selfhosting.CreateSelfHostedControlPlane(internalcfg, client)
kubeadmutil.CheckErr(err) kubeadmutil.CheckErr(err)
}, },
} }

View File

@ -13,10 +13,12 @@ go_test(
srcs = [ srcs = [
"podspec_mutation_test.go", "podspec_mutation_test.go",
"selfhosting_test.go", "selfhosting_test.go",
"selfhosting_volumes_test.go",
], ],
library = ":go_default_library", library = ":go_default_library",
tags = ["automanaged"], tags = ["automanaged"],
deps = [ deps = [
"//cmd/kubeadm/app/apis/kubeadm:go_default_library",
"//cmd/kubeadm/app/constants:go_default_library", "//cmd/kubeadm/app/constants:go_default_library",
"//vendor/github.com/ghodss/yaml:go_default_library", "//vendor/github.com/ghodss/yaml:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library", "//vendor/k8s.io/api/core/v1:go_default_library",
@ -28,9 +30,11 @@ go_library(
srcs = [ srcs = [
"podspec_mutation.go", "podspec_mutation.go",
"selfhosting.go", "selfhosting.go",
"selfhosting_volumes.go",
], ],
tags = ["automanaged"], tags = ["automanaged"],
deps = [ deps = [
"//cmd/kubeadm/app/apis/kubeadm:go_default_library",
"//cmd/kubeadm/app/constants:go_default_library", "//cmd/kubeadm/app/constants:go_default_library",
"//cmd/kubeadm/app/util:go_default_library", "//cmd/kubeadm/app/util:go_default_library",
"//pkg/api:go_default_library", "//pkg/api:go_default_library",

View File

@ -18,38 +18,42 @@ package selfhosting
import ( import (
"k8s.io/api/core/v1" "k8s.io/api/core/v1"
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants" kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
) )
// mutatePodSpec makes a Static Pod-hosted PodSpec suitable for self-hosting // mutatePodSpec makes a Static Pod-hosted PodSpec suitable for self-hosting
func mutatePodSpec(name string, podSpec *v1.PodSpec) { func mutatePodSpec(cfg *kubeadmapi.MasterConfiguration, name string, podSpec *v1.PodSpec) {
mutators := map[string][]func(*v1.PodSpec){ mutators := map[string][]func(*kubeadmapi.MasterConfiguration, *v1.PodSpec){
kubeAPIServer: { kubeAPIServer: {
addNodeSelectorToPodSpec, addNodeSelectorToPodSpec,
setMasterTolerationOnPodSpec, setMasterTolerationOnPodSpec,
setRightDNSPolicyOnPodSpec, setRightDNSPolicyOnPodSpec,
setVolumesOnKubeAPIServerPodSpec,
}, },
kubeControllerManager: { kubeControllerManager: {
addNodeSelectorToPodSpec, addNodeSelectorToPodSpec,
setMasterTolerationOnPodSpec, setMasterTolerationOnPodSpec,
setRightDNSPolicyOnPodSpec, setRightDNSPolicyOnPodSpec,
setVolumesOnKubeControllerManagerPodSpec,
}, },
kubeScheduler: { kubeScheduler: {
addNodeSelectorToPodSpec, addNodeSelectorToPodSpec,
setMasterTolerationOnPodSpec, setMasterTolerationOnPodSpec,
setRightDNSPolicyOnPodSpec, setRightDNSPolicyOnPodSpec,
setVolumesOnKubeSchedulerPodSpec,
}, },
} }
// Get the mutator functions for the component in question, then loop through and execute them // Get the mutator functions for the component in question, then loop through and execute them
mutatorsForComponent := mutators[name] mutatorsForComponent := mutators[name]
for _, mutateFunc := range mutatorsForComponent { for _, mutateFunc := range mutatorsForComponent {
mutateFunc(podSpec) mutateFunc(cfg, podSpec)
} }
} }
// addNodeSelectorToPodSpec makes Pod require to be scheduled on a node marked with the master label // addNodeSelectorToPodSpec makes Pod require to be scheduled on a node marked with the master label
func addNodeSelectorToPodSpec(podSpec *v1.PodSpec) { func addNodeSelectorToPodSpec(cfg *kubeadmapi.MasterConfiguration, podSpec *v1.PodSpec) {
if podSpec.NodeSelector == nil { if podSpec.NodeSelector == nil {
podSpec.NodeSelector = map[string]string{kubeadmconstants.LabelNodeRoleMaster: ""} podSpec.NodeSelector = map[string]string{kubeadmconstants.LabelNodeRoleMaster: ""}
return return
@ -59,7 +63,7 @@ func addNodeSelectorToPodSpec(podSpec *v1.PodSpec) {
} }
// setMasterTolerationOnPodSpec makes the Pod tolerate the master taint // setMasterTolerationOnPodSpec makes the Pod tolerate the master taint
func setMasterTolerationOnPodSpec(podSpec *v1.PodSpec) { func setMasterTolerationOnPodSpec(cfg *kubeadmapi.MasterConfiguration, podSpec *v1.PodSpec) {
if podSpec.Tolerations == nil { if podSpec.Tolerations == nil {
podSpec.Tolerations = []v1.Toleration{kubeadmconstants.MasterToleration} podSpec.Tolerations = []v1.Toleration{kubeadmconstants.MasterToleration}
return return
@ -69,6 +73,38 @@ func setMasterTolerationOnPodSpec(podSpec *v1.PodSpec) {
} }
// setRightDNSPolicyOnPodSpec makes sure the self-hosted components can look up things via kube-dns if necessary // setRightDNSPolicyOnPodSpec makes sure the self-hosted components can look up things via kube-dns if necessary
func setRightDNSPolicyOnPodSpec(podSpec *v1.PodSpec) { func setRightDNSPolicyOnPodSpec(cfg *kubeadmapi.MasterConfiguration, podSpec *v1.PodSpec) {
podSpec.DNSPolicy = v1.DNSClusterFirstWithHostNet podSpec.DNSPolicy = v1.DNSClusterFirstWithHostNet
} }
// setVolumesOnKubeAPIServerPodSpec makes sure the self-hosted api server has the required files
func setVolumesOnKubeAPIServerPodSpec(cfg *kubeadmapi.MasterConfiguration, podSpec *v1.PodSpec) {
setK8sVolume(apiServerProjectedVolume, cfg, podSpec)
for _, c := range podSpec.Containers {
c.VolumeMounts = append(c.VolumeMounts, k8sSelfHostedVolumeMount())
}
}
// setVolumesOnKubeControllerManagerPodSpec makes sure the self-hosted controller manager has the required files
func setVolumesOnKubeControllerManagerPodSpec(cfg *kubeadmapi.MasterConfiguration, podSpec *v1.PodSpec) {
setK8sVolume(controllerManagerProjectedVolume, cfg, podSpec)
for _, c := range podSpec.Containers {
c.VolumeMounts = append(c.VolumeMounts, k8sSelfHostedVolumeMount())
}
}
// setVolumesOnKubeSchedulerPodSpec makes sure the self-hosted scheduler has the required files
func setVolumesOnKubeSchedulerPodSpec(cfg *kubeadmapi.MasterConfiguration, podSpec *v1.PodSpec) {
setK8sVolume(schedulerProjectedVolume, cfg, podSpec)
for _, c := range podSpec.Containers {
c.VolumeMounts = append(c.VolumeMounts, k8sSelfHostedVolumeMount())
}
}
func setK8sVolume(cb func(cfg *kubeadmapi.MasterConfiguration) v1.Volume, cfg *kubeadmapi.MasterConfiguration, podSpec *v1.PodSpec) {
for i, v := range podSpec.Volumes {
if v.Name == "k8s" {
podSpec.Volumes[i] = cb(cfg)
}
}
}

View File

@ -21,6 +21,7 @@ import (
"testing" "testing"
"k8s.io/api/core/v1" "k8s.io/api/core/v1"
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants" kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
) )
@ -71,8 +72,9 @@ func TestMutatePodSpec(t *testing.T) {
}, },
} }
cfg := &kubeadmapi.MasterConfiguration{}
for _, rt := range tests { for _, rt := range tests {
mutatePodSpec(rt.component, rt.podSpec) mutatePodSpec(cfg, rt.component, rt.podSpec)
if !reflect.DeepEqual(*rt.podSpec, rt.expected) { if !reflect.DeepEqual(*rt.podSpec, rt.expected) {
t.Errorf("failed mutatePodSpec:\nexpected:\n%v\nsaw:\n%v", rt.expected, *rt.podSpec) t.Errorf("failed mutatePodSpec:\nexpected:\n%v\nsaw:\n%v", rt.expected, *rt.podSpec)
@ -108,8 +110,9 @@ func TestAddNodeSelectorToPodSpec(t *testing.T) {
}, },
} }
cfg := &kubeadmapi.MasterConfiguration{}
for _, rt := range tests { for _, rt := range tests {
addNodeSelectorToPodSpec(rt.podSpec) addNodeSelectorToPodSpec(cfg, rt.podSpec)
if !reflect.DeepEqual(*rt.podSpec, rt.expected) { if !reflect.DeepEqual(*rt.podSpec, rt.expected) {
t.Errorf("failed addNodeSelectorToPodSpec:\nexpected:\n%v\nsaw:\n%v", rt.expected, *rt.podSpec) t.Errorf("failed addNodeSelectorToPodSpec:\nexpected:\n%v\nsaw:\n%v", rt.expected, *rt.podSpec)
@ -145,8 +148,9 @@ func TestSetMasterTolerationOnPodSpec(t *testing.T) {
}, },
} }
cfg := &kubeadmapi.MasterConfiguration{}
for _, rt := range tests { for _, rt := range tests {
setMasterTolerationOnPodSpec(rt.podSpec) setMasterTolerationOnPodSpec(cfg, rt.podSpec)
if !reflect.DeepEqual(*rt.podSpec, rt.expected) { if !reflect.DeepEqual(*rt.podSpec, rt.expected) {
t.Errorf("failed setMasterTolerationOnPodSpec:\nexpected:\n%v\nsaw:\n%v", rt.expected, *rt.podSpec) t.Errorf("failed setMasterTolerationOnPodSpec:\nexpected:\n%v\nsaw:\n%v", rt.expected, *rt.podSpec)
@ -175,8 +179,9 @@ func TestSetRightDNSPolicyOnPodSpec(t *testing.T) {
}, },
} }
cfg := &kubeadmapi.MasterConfiguration{}
for _, rt := range tests { for _, rt := range tests {
setRightDNSPolicyOnPodSpec(rt.podSpec) setRightDNSPolicyOnPodSpec(cfg, rt.podSpec)
if !reflect.DeepEqual(*rt.podSpec, rt.expected) { if !reflect.DeepEqual(*rt.podSpec, rt.expected) {
t.Errorf("failed setRightDNSPolicyOnPodSpec:\nexpected:\n%v\nsaw:\n%v", rt.expected, *rt.podSpec) t.Errorf("failed setRightDNSPolicyOnPodSpec:\nexpected:\n%v\nsaw:\n%v", rt.expected, *rt.podSpec)

View File

@ -29,6 +29,7 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
kuberuntime "k8s.io/apimachinery/pkg/runtime" kuberuntime "k8s.io/apimachinery/pkg/runtime"
clientset "k8s.io/client-go/kubernetes" clientset "k8s.io/client-go/kubernetes"
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants" kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util" kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
@ -53,7 +54,15 @@ const (
// 7. The self-hosted containers should now step up and take over. // 7. The self-hosted containers should now step up and take over.
// 8. In order to avoid race conditions, we're still making sure the API /healthz endpoint is healthy // 8. In order to avoid race conditions, we're still making sure the API /healthz endpoint is healthy
// 9. Do that for the kube-apiserver, kube-controller-manager and kube-scheduler in a loop // 9. Do that for the kube-apiserver, kube-controller-manager and kube-scheduler in a loop
func CreateSelfHostedControlPlane(client *clientset.Clientset) error { func CreateSelfHostedControlPlane(cfg *kubeadmapi.MasterConfiguration, client *clientset.Clientset) error {
if err := createTLSSecrets(cfg, client); err != nil {
return err
}
if err := createOpaqueSecrets(cfg, client); err != nil {
return err
}
// The sequence here isn't set in stone, but seems to work well to start with the API server // The sequence here isn't set in stone, but seems to work well to start with the API server
components := []string{kubeAPIServer, kubeControllerManager, kubeScheduler} components := []string{kubeAPIServer, kubeControllerManager, kubeScheduler}
@ -69,7 +78,7 @@ func CreateSelfHostedControlPlane(client *clientset.Clientset) error {
} }
// Build a DaemonSet object from the loaded PodSpec // Build a DaemonSet object from the loaded PodSpec
ds := buildDaemonSet(componentName, podSpec) ds := buildDaemonSet(cfg, componentName, podSpec)
// Create the DaemonSet in the API Server // Create the DaemonSet in the API Server
if _, err := client.ExtensionsV1beta1().DaemonSets(metav1.NamespaceSystem).Create(ds); err != nil { if _, err := client.ExtensionsV1beta1().DaemonSets(metav1.NamespaceSystem).Create(ds); err != nil {
@ -100,9 +109,9 @@ func CreateSelfHostedControlPlane(client *clientset.Clientset) error {
} }
// buildDaemonSet is responsible for mutating the PodSpec and return a DaemonSet which is suitable for the self-hosting purporse // buildDaemonSet is responsible for mutating the PodSpec and return a DaemonSet which is suitable for the self-hosting purporse
func buildDaemonSet(name string, podSpec *v1.PodSpec) *extensions.DaemonSet { func buildDaemonSet(cfg *kubeadmapi.MasterConfiguration, name string, podSpec *v1.PodSpec) *extensions.DaemonSet {
// Mutate the PodSpec so it's suitable for self-hosting // Mutate the PodSpec so it's suitable for self-hosting
mutatePodSpec(name, podSpec) mutatePodSpec(cfg, name, podSpec)
// Return a DaemonSet based on that Spec // Return a DaemonSet based on that Spec
return &extensions.DaemonSet{ return &extensions.DaemonSet{

View File

@ -24,6 +24,7 @@ import (
"testing" "testing"
"github.com/ghodss/yaml" "github.com/ghodss/yaml"
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
) )
const ( const (
@ -90,9 +91,49 @@ spec:
name: pki name: pki
hostNetwork: true hostNetwork: true
volumes: volumes:
- hostPath: - name: k8s
path: /etc/kubernetes projected:
name: k8s sources:
- secret:
items:
- key: tls.crt
path: ca.crt
- key: tls.key
path: ca.key
name: ca
- secret:
items:
- key: tls.crt
path: apiserver.crt
- key: tls.key
path: apiserver.key
name: apiserver
- secret:
items:
- key: tls.crt
path: apiserver-kubelet-client.crt
- key: tls.key
path: apiserver-kubelet-client.key
name: apiserver-kubelet-client
- secret:
items:
- key: tls.crt
path: sa.pub
- key: tls.key
path: sa.key
name: sa
- secret:
items:
- key: tls.crt
path: front-proxy-ca.crt
name: front-proxy-ca
- secret:
items:
- key: tls.crt
path: front-proxy-client.crt
- key: tls.key
path: front-proxy-client.key
name: front-proxy-client
- hostPath: - hostPath:
path: /etc/ssl/certs path: /etc/ssl/certs
name: certs name: certs
@ -171,9 +212,49 @@ spec:
- effect: NoSchedule - effect: NoSchedule
key: node-role.kubernetes.io/master key: node-role.kubernetes.io/master
volumes: volumes:
- hostPath: - name: k8s
path: /etc/kubernetes projected:
name: k8s sources:
- secret:
items:
- key: tls.crt
path: ca.crt
- key: tls.key
path: ca.key
name: ca
- secret:
items:
- key: tls.crt
path: apiserver.crt
- key: tls.key
path: apiserver.key
name: apiserver
- secret:
items:
- key: tls.crt
path: apiserver-kubelet-client.crt
- key: tls.key
path: apiserver-kubelet-client.key
name: apiserver-kubelet-client
- secret:
items:
- key: tls.crt
path: sa.pub
- key: tls.key
path: sa.key
name: sa
- secret:
items:
- key: tls.crt
path: front-proxy-ca.crt
name: front-proxy-ca
- secret:
items:
- key: tls.crt
path: front-proxy-client.crt
- key: tls.key
path: front-proxy-client.key
name: front-proxy-client
- hostPath: - hostPath:
path: /etc/ssl/certs path: /etc/ssl/certs
name: certs name: certs
@ -237,9 +318,23 @@ spec:
name: pki name: pki
hostNetwork: true hostNetwork: true
volumes: volumes:
- hostPath: - name: k8s
path: /etc/kubernetes projected:
name: k8s sources:
- secret:
name: controller-manager.conf
- secret:
items:
- key: tls.crt
path: ca.crt
- key: tls.key
path: ca.key
name: ca
- secret:
items:
- key: tls.key
path: sa.key
name: sa
- hostPath: - hostPath:
path: /etc/ssl/certs path: /etc/ssl/certs
name: certs name: certs
@ -304,9 +399,23 @@ spec:
- effect: NoSchedule - effect: NoSchedule
key: node-role.kubernetes.io/master key: node-role.kubernetes.io/master
volumes: volumes:
- hostPath: - name: k8s
path: /etc/kubernetes projected:
name: k8s sources:
- secret:
name: controller-manager.conf
- secret:
items:
- key: tls.crt
path: ca.crt
- key: tls.key
path: ca.key
name: ca
- secret:
items:
- key: tls.key
path: sa.key
name: sa
- hostPath: - hostPath:
path: /etc/ssl/certs path: /etc/ssl/certs
name: certs name: certs
@ -360,9 +469,11 @@ spec:
readOnly: true readOnly: true
hostNetwork: true hostNetwork: true
volumes: volumes:
- hostPath: - name: k8s
path: /etc/kubernetes projected:
name: k8s sources:
- secret:
name: scheduler.conf
status: {} status: {}
` `
@ -411,9 +522,11 @@ spec:
- effect: NoSchedule - effect: NoSchedule
key: node-role.kubernetes.io/master key: node-role.kubernetes.io/master
volumes: volumes:
- hostPath: - name: k8s
path: /etc/kubernetes projected:
name: k8s sources:
- secret:
name: scheduler.conf
updateStrategy: {} updateStrategy: {}
status: status:
currentNumberScheduled: 0 currentNumberScheduled: 0
@ -455,7 +568,8 @@ func TestBuildDaemonSet(t *testing.T) {
t.Fatalf("couldn't load the specified Pod") t.Fatalf("couldn't load the specified Pod")
} }
ds := buildDaemonSet(rt.component, podSpec) cfg := &kubeadmapi.MasterConfiguration{}
ds := buildDaemonSet(cfg, rt.component, podSpec)
dsBytes, err := yaml.Marshal(ds) dsBytes, err := yaml.Marshal(ds)
if err != nil { if err != nil {
t.Fatalf("failed to marshal daemonset to YAML: %v", err) t.Fatalf("failed to marshal daemonset to YAML: %v", err)

View File

@ -0,0 +1,340 @@
/*
Copyright 2017 The Kubernetes 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 selfhosting
import (
"fmt"
"io/ioutil"
"path"
"k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
clientset "k8s.io/client-go/kubernetes"
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
)
type tlsKeyPair struct {
name string
cert string
key string
}
func k8sSelfHostedVolumeMount() v1.VolumeMount {
return v1.VolumeMount{
Name: "k8s",
MountPath: kubeadmapi.GlobalEnvParams.KubernetesDir,
ReadOnly: true,
}
}
func apiServerProjectedVolume(cfg *kubeadmapi.MasterConfiguration) v1.Volume {
return v1.Volume{
Name: "k8s",
VolumeSource: v1.VolumeSource{
Projected: &v1.ProjectedVolumeSource{
Sources: []v1.VolumeProjection{
{
Secret: &v1.SecretProjection{
LocalObjectReference: v1.LocalObjectReference{
Name: kubeadmconstants.CACertAndKeyBaseName,
},
Items: []v1.KeyToPath{
{
Key: v1.TLSCertKey,
Path: path.Join(path.Base(cfg.CertificatesDir), kubeadmconstants.CACertName),
},
{
Key: v1.TLSPrivateKeyKey,
Path: path.Join(path.Base(cfg.CertificatesDir), kubeadmconstants.CAKeyName),
},
},
},
},
{
Secret: &v1.SecretProjection{
LocalObjectReference: v1.LocalObjectReference{
Name: kubeadmconstants.APIServerCertAndKeyBaseName,
},
Items: []v1.KeyToPath{
{
Key: v1.TLSCertKey,
Path: path.Join(path.Base(cfg.CertificatesDir), kubeadmconstants.APIServerCertName),
},
{
Key: v1.TLSPrivateKeyKey,
Path: path.Join(path.Base(cfg.CertificatesDir), kubeadmconstants.APIServerKeyName),
},
},
},
},
{
Secret: &v1.SecretProjection{
LocalObjectReference: v1.LocalObjectReference{
Name: kubeadmconstants.APIServerKubeletClientCertAndKeyBaseName,
},
Items: []v1.KeyToPath{
{
Key: v1.TLSCertKey,
Path: path.Join(path.Base(cfg.CertificatesDir), kubeadmconstants.APIServerKubeletClientCertName),
},
{
Key: v1.TLSPrivateKeyKey,
Path: path.Join(path.Base(cfg.CertificatesDir), kubeadmconstants.APIServerKubeletClientKeyName),
},
},
},
},
{
Secret: &v1.SecretProjection{
LocalObjectReference: v1.LocalObjectReference{
Name: kubeadmconstants.ServiceAccountKeyBaseName,
},
Items: []v1.KeyToPath{
{
Key: v1.TLSCertKey,
Path: path.Join(path.Base(cfg.CertificatesDir), kubeadmconstants.ServiceAccountPublicKeyName),
},
{
Key: v1.TLSPrivateKeyKey,
Path: path.Join(path.Base(cfg.CertificatesDir), kubeadmconstants.ServiceAccountPrivateKeyName),
},
},
},
},
{
Secret: &v1.SecretProjection{
LocalObjectReference: v1.LocalObjectReference{
Name: kubeadmconstants.FrontProxyCACertAndKeyBaseName,
},
Items: []v1.KeyToPath{
{
Key: v1.TLSCertKey,
Path: path.Join(path.Base(cfg.CertificatesDir), kubeadmconstants.FrontProxyCACertName),
},
},
},
},
{
Secret: &v1.SecretProjection{
LocalObjectReference: v1.LocalObjectReference{
Name: kubeadmconstants.FrontProxyClientCertAndKeyBaseName,
},
Items: []v1.KeyToPath{
{
Key: v1.TLSCertKey,
Path: path.Join(path.Base(cfg.CertificatesDir), kubeadmconstants.FrontProxyClientCertName),
},
{
Key: v1.TLSPrivateKeyKey,
Path: path.Join(path.Base(cfg.CertificatesDir), kubeadmconstants.FrontProxyClientKeyName),
},
},
},
},
},
},
},
}
}
func schedulerProjectedVolume(cfg *kubeadmapi.MasterConfiguration) v1.Volume {
return v1.Volume{
Name: "k8s",
VolumeSource: v1.VolumeSource{
Projected: &v1.ProjectedVolumeSource{
Sources: []v1.VolumeProjection{
{
Secret: &v1.SecretProjection{
LocalObjectReference: v1.LocalObjectReference{
Name: kubeadmconstants.SchedulerKubeConfigFileName,
},
},
},
},
},
},
}
}
func controllerManagerProjectedVolume(cfg *kubeadmapi.MasterConfiguration) v1.Volume {
return v1.Volume{
Name: "k8s",
VolumeSource: v1.VolumeSource{
Projected: &v1.ProjectedVolumeSource{
Sources: []v1.VolumeProjection{
{
Secret: &v1.SecretProjection{
LocalObjectReference: v1.LocalObjectReference{
Name: kubeadmconstants.ControllerManagerKubeConfigFileName,
},
},
},
{
Secret: &v1.SecretProjection{
LocalObjectReference: v1.LocalObjectReference{
Name: kubeadmconstants.CACertAndKeyBaseName,
},
Items: []v1.KeyToPath{
{
Key: v1.TLSCertKey,
Path: path.Join(path.Base(cfg.CertificatesDir), kubeadmconstants.CACertName),
},
{
Key: v1.TLSPrivateKeyKey,
Path: path.Join(path.Base(cfg.CertificatesDir), kubeadmconstants.CAKeyName),
},
},
},
},
{
Secret: &v1.SecretProjection{
LocalObjectReference: v1.LocalObjectReference{
Name: kubeadmconstants.ServiceAccountKeyBaseName,
},
Items: []v1.KeyToPath{
{
Key: v1.TLSPrivateKeyKey,
Path: path.Join(path.Base(cfg.CertificatesDir), kubeadmconstants.ServiceAccountPrivateKeyName),
},
},
},
},
},
},
},
}
}
func createTLSSecrets(cfg *kubeadmapi.MasterConfiguration, client *clientset.Clientset) error {
for _, tlsKeyPair := range getTLSKeyPairs() {
secret, err := createTLSSecretFromFiles(
tlsKeyPair.name,
path.Join(cfg.CertificatesDir, tlsKeyPair.cert),
path.Join(cfg.CertificatesDir, tlsKeyPair.key),
)
if err != nil {
return err
}
if _, err := client.CoreV1().Secrets(metav1.NamespaceSystem).Create(secret); err != nil {
return err
}
fmt.Printf("[self-hosted] Created TLS secret %q from %s and %s\n", tlsKeyPair.name, tlsKeyPair.cert, tlsKeyPair.key)
}
return nil
}
func createOpaqueSecrets(cfg *kubeadmapi.MasterConfiguration, client *clientset.Clientset) error {
files := []string{
kubeadmconstants.SchedulerKubeConfigFileName,
kubeadmconstants.ControllerManagerKubeConfigFileName,
}
for _, file := range files {
secret, err := createOpaqueSecretFromFile(
file,
path.Join(kubeadmapi.GlobalEnvParams.KubernetesDir, file),
)
if err != nil {
return err
}
if _, err := client.CoreV1().Secrets(metav1.NamespaceSystem).Create(secret); err != nil {
return err
}
fmt.Printf("[self-hosted] Created secret %q\n", file)
}
return nil
}
func createTLSSecretFromFiles(secretName, crt, key string) (*v1.Secret, error) {
crtBytes, err := ioutil.ReadFile(crt)
if err != nil {
return nil, err
}
keyBytes, err := ioutil.ReadFile(key)
if err != nil {
return nil, err
}
return &v1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: secretName,
Namespace: metav1.NamespaceSystem,
},
Type: v1.SecretTypeTLS,
Data: map[string][]byte{
v1.TLSCertKey: crtBytes,
v1.TLSPrivateKeyKey: keyBytes,
},
}, nil
}
func createOpaqueSecretFromFile(secretName, file string) (*v1.Secret, error) {
fileBytes, err := ioutil.ReadFile(file)
if err != nil {
return nil, err
}
return &v1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: secretName,
Namespace: metav1.NamespaceSystem,
},
Type: v1.SecretTypeOpaque,
Data: map[string][]byte{
path.Base(file): fileBytes,
},
}, nil
}
func getTLSKeyPairs() []*tlsKeyPair {
return []*tlsKeyPair{
{
name: kubeadmconstants.CACertAndKeyBaseName,
cert: kubeadmconstants.CACertName,
key: kubeadmconstants.CAKeyName,
},
{
name: kubeadmconstants.APIServerCertAndKeyBaseName,
cert: kubeadmconstants.APIServerCertName,
key: kubeadmconstants.APIServerKeyName,
},
{
name: kubeadmconstants.APIServerKubeletClientCertAndKeyBaseName,
cert: kubeadmconstants.APIServerKubeletClientCertName,
key: kubeadmconstants.APIServerKubeletClientKeyName,
},
{
name: kubeadmconstants.ServiceAccountKeyBaseName,
cert: kubeadmconstants.ServiceAccountPublicKeyName,
key: kubeadmconstants.ServiceAccountPrivateKeyName,
},
{
name: kubeadmconstants.FrontProxyCACertAndKeyBaseName,
cert: kubeadmconstants.FrontProxyCACertName,
key: kubeadmconstants.FrontProxyCAKeyName,
},
{
name: kubeadmconstants.FrontProxyClientCertAndKeyBaseName,
cert: kubeadmconstants.FrontProxyClientCertName,
key: kubeadmconstants.FrontProxyClientKeyName,
},
}
}

View File

@ -0,0 +1,72 @@
/*
Copyright 2017 The Kubernetes 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 selfhosting
import (
"io/ioutil"
"log"
"os"
"testing"
)
func createTemporaryFile(name string) *os.File {
content := []byte("foo")
tmpfile, err := ioutil.TempFile("", name)
if err != nil {
log.Fatal(err)
}
if _, err := tmpfile.Write(content); err != nil {
log.Fatal(err)
}
return tmpfile
}
func TestCreateTLSSecretFromFile(t *testing.T) {
tmpCert := createTemporaryFile("foo.crt")
defer os.Remove(tmpCert.Name())
tmpKey := createTemporaryFile("foo.key")
defer os.Remove(tmpKey.Name())
_, err := createTLSSecretFromFiles("foo", tmpCert.Name(), tmpKey.Name())
if err != nil {
log.Fatal(err)
}
if err := tmpCert.Close(); err != nil {
log.Fatal(err)
}
if err := tmpKey.Close(); err != nil {
log.Fatal(err)
}
}
func TestCreateOpaqueSecretFromFile(t *testing.T) {
tmpFile := createTemporaryFile("foo")
defer os.Remove(tmpFile.Name())
_, err := createOpaqueSecretFromFile("foo", tmpFile.Name())
if err != nil {
log.Fatal(err)
}
if err := tmpFile.Close(); err != nil {
log.Fatal(err)
}
}