diff --git a/contrib/metallb/README.md b/contrib/metallb/README.md new file mode 100644 index 000000000..7095d58f8 --- /dev/null +++ b/contrib/metallb/README.md @@ -0,0 +1,10 @@ +# Deploy MetalLB into Kubespray/Kubernetes +``` +MetalLB hooks into your Kubernetes cluster, and provides a network load-balancer implementation. In short, it allows you to create Kubernetes services of type “LoadBalancer” in clusters that don’t run on a cloud provider, and thus cannot simply hook into paid products to provide load-balancers. +``` +This playbook aims to automate [this](https://metallb.universe.tf/tutorial/layer2/tutorial). It deploys MetalLB into kubernetes and sets up a layer 2 loadbalancer. + +## Install +``` +ansible-playbook --ask-become -i inventory/sample/k8s_heketi_inventory.yml contrib/metallb/metallb.yml +``` diff --git a/contrib/metallb/metallb.yml b/contrib/metallb/metallb.yml new file mode 100644 index 000000000..618a1d223 --- /dev/null +++ b/contrib/metallb/metallb.yml @@ -0,0 +1,6 @@ +--- +- hosts: kube-master[0] + tags: + - "provision" + roles: + - { role: provision } diff --git a/contrib/metallb/roles/provision/defaults/main.yml b/contrib/metallb/roles/provision/defaults/main.yml new file mode 100644 index 000000000..c7d0bf904 --- /dev/null +++ b/contrib/metallb/roles/provision/defaults/main.yml @@ -0,0 +1,7 @@ +--- +metallb: + ip_range: "10.5.0.50-10.5.0.99" + limits: + cpu: "100m" + memory: "100Mi" + port: "7472" diff --git a/contrib/metallb/roles/provision/tasks/main.yml b/contrib/metallb/roles/provision/tasks/main.yml new file mode 100644 index 000000000..47c4b624a --- /dev/null +++ b/contrib/metallb/roles/provision/tasks/main.yml @@ -0,0 +1,16 @@ +--- +- name: "Kubernetes Apps | Lay Down MetalLB" + become: true + template: { src: "{{ item }}.j2", dest: "{{ kube_config_dir }}/{{ item }}" } + with_items: ["metallb.yml", "metallb-config.yml"] + register: "rendering" + when: + - "inventory_hostname == groups['kube-master'][0]" +- name: "Kubernetes Apps | Install and configure MetalLB" + kube: + name: "MetalLB" + filename: "{{ kube_config_dir }}/metallb.yml" + state: "{{ item.changed | ternary('latest','present') }}" + with_items: "{{ rendering.results }}" + when: + - "inventory_hostname == groups['kube-master'][0]" diff --git a/contrib/metallb/roles/provision/templates/metallb-config.yml.j2 b/contrib/metallb/roles/provision/templates/metallb-config.yml.j2 new file mode 100644 index 000000000..2e58f2d5f --- /dev/null +++ b/contrib/metallb/roles/provision/templates/metallb-config.yml.j2 @@ -0,0 +1,13 @@ +--- +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: metallb-system + name: config +data: + config: | + address-pools: + - name: loadbalanced + protocol: layer2 + addresses: + - {{ metallb.ip_range }} diff --git a/contrib/metallb/roles/provision/templates/metallb.yml.j2 b/contrib/metallb/roles/provision/templates/metallb.yml.j2 new file mode 100644 index 000000000..c9532f014 --- /dev/null +++ b/contrib/metallb/roles/provision/templates/metallb.yml.j2 @@ -0,0 +1,254 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: metallb-system + labels: + app: metallb +--- + +apiVersion: v1 +kind: ServiceAccount +metadata: + namespace: metallb-system + name: controller + labels: + app: metallb +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + namespace: metallb-system + name: speaker + labels: + app: metallb + +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: metallb-system:controller + labels: + app: metallb +rules: +- apiGroups: [""] + resources: ["services"] + verbs: ["get", "list", "watch", "update"] +- apiGroups: [""] + resources: ["services/status"] + verbs: ["update"] +- apiGroups: [""] + resources: ["events"] + verbs: ["create", "patch"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: metallb-system:speaker + labels: + app: metallb +rules: +- apiGroups: [""] + resources: ["services", "endpoints", "nodes"] + verbs: ["get", "list", "watch"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + namespace: metallb-system + name: leader-election + labels: + app: metallb +rules: +- apiGroups: [""] + resources: ["endpoints"] + resourceNames: ["metallb-speaker"] + verbs: ["get", "update"] +- apiGroups: [""] + resources: ["endpoints"] + verbs: ["create"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + namespace: metallb-system + name: config-watcher + labels: + app: metallb +rules: +- apiGroups: [""] + resources: ["configmaps"] + verbs: ["get", "list", "watch"] +- apiGroups: [""] + resources: ["events"] + verbs: ["create"] +--- + +## Role bindings +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: metallb-system:controller + labels: + app: metallb +subjects: +- kind: ServiceAccount + name: controller + namespace: metallb-system +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: metallb-system:controller +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: metallb-system:speaker + labels: + app: metallb +subjects: +- kind: ServiceAccount + name: speaker + namespace: metallb-system +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: metallb-system:speaker +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + namespace: metallb-system + name: config-watcher + labels: + app: metallb +subjects: +- kind: ServiceAccount + name: controller +- kind: ServiceAccount + name: speaker +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: config-watcher +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + namespace: metallb-system + name: leader-election + labels: + app: metallb +subjects: +- kind: ServiceAccount + name: speaker +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: leader-election +--- +apiVersion: apps/v1beta2 +kind: DaemonSet +metadata: + namespace: metallb-system + name: speaker + labels: + app: metallb + component: speaker +spec: + selector: + matchLabels: + app: metallb + component: speaker + template: + metadata: + labels: + app: metallb + component: speaker + annotations: + prometheus.io/scrape: "true" + prometheus.io/port: "{{ metallb.port }}" + spec: + serviceAccountName: speaker + terminationGracePeriodSeconds: 0 + hostNetwork: true + containers: + - name: speaker + image: metallb/speaker:v0.6.2 + imagePullPolicy: IfNotPresent + args: + - --port={{ metallb.port }} + - --config=config + env: + - name: METALLB_NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + ports: + - name: monitoring + containerPort: {{ metallb.port }} + resources: + limits: + cpu: {{ metallb.limits.cpu }} + memory: {{ metallb.limits.memory }} + securityContext: + allowPrivilegeEscalation: false + readOnlyRootFilesystem: true + capabilities: + drop: + - all + add: + - net_raw + +--- +apiVersion: apps/v1beta2 +kind: Deployment +metadata: + namespace: metallb-system + name: controller + labels: + app: metallb + component: controller +spec: + revisionHistoryLimit: 3 + selector: + matchLabels: + app: metallb + component: controller + template: + metadata: + labels: + app: metallb + component: controller + annotations: + prometheus.io/scrape: "true" + prometheus.io/port: "{{ metallb.port }}" + spec: + serviceAccountName: controller + terminationGracePeriodSeconds: 0 + securityContext: + runAsNonRoot: true + runAsUser: 65534 # nobody + containers: + - name: controller + image: metallb/controller:v0.6.2 + imagePullPolicy: IfNotPresent + args: + - --port={{ metallb.port }} + - --config=config + ports: + - name: monitoring + containerPort: {{ metallb.port }} + resources: + limits: + cpu: {{ metallb.limits.cpu }} + memory: {{ metallb.limits.memory }} + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - all + readOnlyRootFilesystem: true + +--- + +