| # Deploy MetalLB |
| |
| local kube = import "../../../kube/kube.libsonnet"; |
| local policies = import "../../../kube/policies.libsonnet"; |
| |
| local bindServiceAccountClusterRole(sa, cr) = kube.ClusterRoleBinding(cr.metadata.name) { |
| roleRef: { |
| apiGroup: "rbac.authorization.k8s.io", |
| kind: "ClusterRole", |
| name: cr.metadata.name, |
| }, |
| subjects: [ |
| { |
| kind: "ServiceAccount", |
| name: sa.metadata.name, |
| namespace: sa.metadata.namespace, |
| }, |
| ], |
| }; |
| |
| { |
| Environment: { |
| local env = self, |
| local cfg = env.cfg, |
| cfg:: { |
| namespace: "metallb-system", |
| namespaceCreate: true, |
| version:: "v0.8.3", |
| imageController: "metallb/controller:" + cfg.version, |
| //imageSpeaker: "metallb/speaker:" + cfg.version, |
| imageSpeaker: "derq3k/metallb-speaker:20191101-180123", |
| addressPools: error "addressPools must be set in config", |
| }, |
| |
| ns: if cfg.namespaceCreate then kube.Namespace(cfg.namespace), |
| |
| insecurePolicy: policies.AllowNamespaceInsecure(cfg.namespace), |
| |
| saController: kube.ServiceAccount("controller") { |
| metadata+: { |
| namespace: cfg.namespace, |
| }, |
| }, |
| |
| saSpeaker: kube.ServiceAccount("speaker") { |
| metadata+: { |
| namespace: cfg.namespace, |
| }, |
| }, |
| |
| crController: kube.ClusterRole("%s:controller" % cfg.namespace) { |
| rules: [ |
| { |
| apiGroups: [""], |
| resources: ["services"], |
| verbs: ["get", "list", "watch", "update"], |
| }, |
| { |
| apiGroups: [""], |
| resources: ["services/status"], |
| verbs: ["update"], |
| }, |
| { |
| apiGroups: [""], |
| resources: ["events"], |
| verbs: ["create", "patch"], |
| }, |
| ], |
| }, |
| |
| crbController: bindServiceAccountClusterRole(env.saController, env.crController), |
| |
| crSpeaker: kube.ClusterRole("%s:speaker" % cfg.namespace) { |
| rules: [ |
| { |
| apiGroups: [""], |
| resources: ["services", "endpoints", "nodes"], |
| verbs: ["get", "list", "watch"], |
| }, |
| { |
| apiGroups: [""], |
| resources: ["events"], |
| verbs: ["create", "patch"], |
| }, |
| ], |
| }, |
| |
| crbSpeaker: bindServiceAccountClusterRole(env.saSpeaker, env.crSpeaker), |
| |
| roleWatcher: kube.Role("config-watcher") { |
| metadata+: { |
| namespace: cfg.namespace, |
| }, |
| rules: [ |
| { |
| apiGroups: [""], |
| resources: ["configmaps"], |
| verbs: ["get", "list", "watch"], |
| }, |
| { |
| apiGroups: [""], |
| resources: ["events"], |
| verbs: ["create"], |
| }, |
| ], |
| }, |
| |
| rbWatcher: kube.RoleBinding("config-watcher") { |
| metadata+: { |
| namespace: cfg.namespace, |
| }, |
| subjects: [ |
| { kind: "ServiceAccount", name: env.saController.metadata.name }, |
| { kind: "ServiceAccount", name: env.saSpeaker.metadata.name }, |
| ], |
| roleRef: { |
| apiGroup: "rbac.authorization.k8s.io", |
| kind: "Role", |
| name: env.roleWatcher.metadata.name, |
| }, |
| }, |
| |
| deployController: kube.Deployment("controller") { |
| metadata+: { |
| namespace: cfg.namespace, |
| }, |
| spec+: { |
| revisionHistoryLimit: 3, |
| template+: { |
| spec+: { |
| serviceAccountName: env.saController.metadata.name, |
| terminationGracePeriodSeconds: 0, |
| securityContext: { |
| runAsNonRoot: true, |
| runAsUser: 65534, # nobody |
| }, |
| containers_: { |
| controller: kube.Container("controller") { |
| image: cfg.imageController, |
| args: [ "--port=7472", "--config=config" ], |
| ports: [ |
| { name: "monitoring", containerPort: 7472 }, |
| ], |
| resources: { |
| limits: { cpu: "200m", memory: "300Mi" }, |
| }, |
| securityContext: { |
| allowPrivilegeEscalation: false, |
| capabilities: { drop: [ "all" ] }, |
| readOnlyRootFilesystem: true, |
| }, |
| }, |
| }, |
| }, |
| }, |
| }, |
| }, |
| |
| daemonsetSpeaker: kube.DaemonSet("speaker") { |
| metadata+: { |
| namespace: cfg.namespace, |
| }, |
| spec+: { |
| template+: { |
| spec+: { |
| serviceAccountName: env.saSpeaker.metadata.name, |
| hostNetwork: true, |
| containers_: { |
| speaker: kube.Container("speaker") { |
| image: cfg.imageSpeaker, |
| args: [ "--port=7472", "--config=config" ], |
| env_: { |
| METALLB_NODE_NAME: kube.FieldRef("spec.nodeName"), |
| METALLB_HOST: kube.FieldRef("status.hostIP"), |
| }, |
| ports: [ |
| { name: "monitoring", containerPort: 7472 }, |
| ], |
| resources: { |
| limits: { cpu: "200m", memory: "300Mi" }, |
| }, |
| securityContext: { |
| allowPrivilegeEscalation: false, |
| capabilities: { drop: [ "all" ], add: [ "NET_ADMIN", "NET_RAW", "SYS_ADMIN" ] }, |
| readOnlyRootFilesystem: true, |
| }, |
| }, |
| }, |
| }, |
| }, |
| }, |
| }, |
| |
| configMap: kube.ConfigMap("config") { |
| local cm = self, |
| metadata+: { |
| namespace: cfg.namespace, |
| }, |
| data: { |
| config: std.manifestYamlDoc({ |
| "address-pools": cfg.addressPools, |
| "peers": cfg.peers, |
| }), |
| }, |
| }, |
| }, |
| } |