github.phpd.cn/cilium/cilium@v1.6.12/pkg/k8s/init.go (about) 1 // Copyright 2016-2019 Authors of Cilium 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // Package k8s abstracts all Kubernetes specific behaviour 16 package k8s 17 18 import ( 19 "context" 20 "fmt" 21 "os" 22 "time" 23 24 "github.com/cilium/cilium/pkg/backoff" 25 cilium_v2 "github.com/cilium/cilium/pkg/k8s/apis/cilium.io/v2" 26 "github.com/cilium/cilium/pkg/k8s/types" 27 k8sversion "github.com/cilium/cilium/pkg/k8s/version" 28 "github.com/cilium/cilium/pkg/logging/logfields" 29 "github.com/cilium/cilium/pkg/node" 30 "github.com/cilium/cilium/pkg/option" 31 "github.com/cilium/cilium/pkg/source" 32 33 "github.com/sirupsen/logrus" 34 apiextensionsclient "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset" 35 ) 36 37 const ( 38 nodeRetrievalMaxRetries = 15 39 ) 40 41 func waitForNodeInformation(nodeName string) *node.Node { 42 backoff := backoff.Exponential{ 43 Min: time.Duration(200) * time.Millisecond, 44 Factor: 2.0, 45 Name: "k8s-node-retrieval", 46 } 47 48 for retry := 0; retry < nodeRetrievalMaxRetries; retry++ { 49 n, err := retrieveNodeInformation(nodeName) 50 if err != nil { 51 log.WithError(err).Warning("Waiting for k8s node information") 52 backoff.Wait(context.TODO()) 53 continue 54 } 55 56 return n 57 } 58 59 return nil 60 } 61 62 func retrieveNodeInformation(nodeName string) (*node.Node, error) { 63 requireIPv4CIDR := option.Config.K8sRequireIPv4PodCIDR 64 requireIPv6CIDR := option.Config.K8sRequireIPv6PodCIDR 65 66 k8sNode, err := GetNode(Client(), nodeName) 67 if err != nil { 68 // If no CIDR is required, retrieving the node information is 69 // optional 70 if !requireIPv4CIDR && !requireIPv6CIDR { 71 return nil, nil 72 } 73 74 return nil, fmt.Errorf("unable to retrieve k8s node information: %s", err) 75 76 } 77 78 nodeInterface := ConvertToNode(k8sNode) 79 if nodeInterface == nil { 80 // This will never happen and the GetNode on line 63 will be soon 81 // make a request from the local store instead. 82 return nil, fmt.Errorf("invalid k8s node: %s", k8sNode) 83 } 84 typesNode := nodeInterface.(*types.Node) 85 86 // The source is left unspecified as this node resource should never be 87 // used to update state 88 n := ParseNode(typesNode, source.Unspec) 89 log.WithField(logfields.NodeName, n.Name).Info("Retrieved node information from kubernetes") 90 91 if requireIPv4CIDR && n.IPv4AllocCIDR == nil { 92 return nil, fmt.Errorf("required IPv4 pod CIDR not present in node resource") 93 } 94 95 if requireIPv6CIDR && n.IPv6AllocCIDR == nil { 96 return nil, fmt.Errorf("required IPv6 pod CIDR not present in node resource") 97 } 98 99 return n, nil 100 } 101 102 // useNodeCIDR sets the ipv4-range and ipv6-range values values from the 103 // addresses defined in the given node. 104 func useNodeCIDR(n *node.Node) { 105 if n.IPv4AllocCIDR != nil && option.Config.EnableIPv4 { 106 node.SetIPv4AllocRange(n.IPv4AllocCIDR) 107 } 108 if n.IPv6AllocCIDR != nil && option.Config.EnableIPv6 { 109 if err := node.SetIPv6NodeRange(n.IPv6AllocCIDR.IPNet); err != nil { 110 log.WithError(err).WithFields(logrus.Fields{ 111 logfields.Node: n.Name, 112 logfields.V6Prefix: n.IPv6AllocCIDR, 113 }).Warn("k8s: Can't use IPv6 CIDR range from k8s") 114 } 115 } 116 } 117 118 // Init initializes the Kubernetes package. It is required to call Configure() 119 // beforehand. 120 func Init() error { 121 if err := createDefaultClient(); err != nil { 122 return fmt.Errorf("unable to create k8s client: %s", err) 123 } 124 125 if err := createDefaultCiliumClient(); err != nil { 126 return fmt.Errorf("unable to create cilium k8s client: %s", err) 127 } 128 129 if err := k8sversion.Update(Client()); err != nil { 130 return err 131 } 132 133 if !k8sversion.Capabilities().MinimalVersionMet { 134 return fmt.Errorf("k8s version (%v) is not meeting the minimal requirement (%v)", 135 k8sversion.Version(), k8sversion.MinimalVersionConstraint) 136 } 137 138 if nodeName := os.Getenv(EnvNodeNameSpec); nodeName != "" { 139 // Use of the environment variable overwrites the node-name 140 // automatically derived 141 node.SetName(nodeName) 142 143 if n := waitForNodeInformation(nodeName); n != nil { 144 nodeIP4 := n.GetNodeIP(false) 145 nodeIP6 := n.GetNodeIP(true) 146 147 log.WithFields(logrus.Fields{ 148 logfields.NodeName: n.Name, 149 logfields.IPAddr + ".ipv4": nodeIP4, 150 logfields.IPAddr + ".ipv6": nodeIP6, 151 logfields.V4Prefix: n.IPv4AllocCIDR, 152 logfields.V6Prefix: n.IPv6AllocCIDR, 153 }).Info("Received own node information from API server") 154 155 useNodeCIDR(n) 156 157 // Note: Node IPs are derived regardless of 158 // option.Config.EnableIPv4 and 159 // option.Config.EnableIPv6. This is done to enable 160 // underlay addressing to be different from overlay 161 // addressing, e.g. an IPv6 only PodCIDR running over 162 // IPv4 encapsulation. 163 if nodeIP4 != nil { 164 node.SetExternalIPv4(nodeIP4) 165 } 166 167 if nodeIP6 != nil { 168 node.SetIPv6(nodeIP6) 169 } 170 } else { 171 // if node resource could not be received, fail if 172 // PodCIDR requirement has been requested 173 if option.Config.K8sRequireIPv4PodCIDR || option.Config.K8sRequireIPv6PodCIDR { 174 log.Fatal("Unable to derive PodCIDR from Kubernetes node resource, giving up") 175 } 176 } 177 178 // Annotate addresses will occur later since the user might 179 // want to specify them manually 180 } else if option.Config.K8sRequireIPv4PodCIDR || option.Config.K8sRequireIPv6PodCIDR { 181 return fmt.Errorf("node name must be specified via environment variable '%s' to retrieve Kubernetes PodCIDR range", EnvNodeNameSpec) 182 } 183 184 return nil 185 } 186 187 // RegisterCRDs registers all CRDs 188 func RegisterCRDs() error { 189 if option.Config.SkipCRDCreation { 190 return nil 191 } 192 193 restConfig, err := CreateConfig() 194 if err != nil { 195 return fmt.Errorf("Unable to create rest configuration: %s", err) 196 } 197 198 apiextensionsclientset, err := apiextensionsclient.NewForConfig(restConfig) 199 if err != nil { 200 return fmt.Errorf("Unable to create rest configuration for k8s CRD: %s", err) 201 } 202 203 err = cilium_v2.CreateCustomResourceDefinitions(apiextensionsclientset) 204 if err != nil { 205 return fmt.Errorf("Unable to create custom resource definition: %s", err) 206 } 207 208 return nil 209 }