diff --git a/README.md b/README.md index 17c9de9..70c4da9 100644 --- a/README.md +++ b/README.md @@ -71,7 +71,7 @@ export FIREWALL_MACHINE_SIZE= metalctl firewall create --description --name --hostname --project $METAL_PROJECT_ID --partition $METAL_PARTITION --image $FIREWALL_MACHINE_IMAGE --size $FIREWALL_MACHINE_SIZE --firewall-rules-file= --networks internet,$METAL_NODE_NETWORK_ID ``` -For your first cluster, it is advised to start with our generated template. +For your first cluster, it is advised to start with our generated template. Ensure that the namespaced cluster name is unique within the metal stack project. ```bash # display required environment variables @@ -125,10 +125,12 @@ spec: EOF ``` -Additionally, the `metal-ccm` has to be deployed for the machines to reach `Running` phase. For this use the [template](capi-lab/metal-ccm.yaml) and fill in the required variables. +Meanwhile, the `metal-ccm` has to be deployed for the machines to reach `Running` phase. For this use the [`config/target-cluster/metal-ccm.yaml` template](config/target-cluster/metal-ccm.yaml) and fill in the required variables. ```bash -cat capi-lab/metal-ccm.yaml | envsubst | kubectl --kubeconfig capms-cluster.kubeconfig apply -f - +export NAMESPACE= +export CLUSTER_NAME= +cat config/target-cluster/metal-ccm.yaml | envsubst | kubectl --kubeconfig capms-cluster.kubeconfig apply -f - ``` If you want to provide service's of type `LoadBalancer` through MetalLB by the `metal-ccm`, you need to deploy MetalLB: @@ -137,8 +139,8 @@ If you want to provide service's of type `LoadBalancer` through MetalLB by the ` kubectl --kubeconfig capms-cluster.kubeconfig apply --kustomize capi-lab/metallb ``` -For each worker node in your Kubernetes cluster, you need to create a BGP peer configuration. Replace the placeholders ({{ -NODE_ASN }}, {{ NODE_HOSTNAME }}, and {{ NODE_ROUTER_ID }}) with the appropriate values for each node. +For each worker node in your Kubernetes cluster, you need to create a BGP peer configuration. Replace the placeholders (`{{ +NODE_ASN }}`, `{{ NODE_HOSTNAME }}`, and `{{ NODE_ROUTER_ID }}`) with the appropriate values for each node. ```bash # in metal-stack, list all machines of your cluster diff --git a/api/v1alpha1/metalstackcluster_types.go b/api/v1alpha1/metalstackcluster_types.go index 7f49d42..52876a9 100644 --- a/api/v1alpha1/metalstackcluster_types.go +++ b/api/v1alpha1/metalstackcluster_types.go @@ -17,6 +17,8 @@ limitations under the License. package v1alpha1 import ( + "fmt" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" @@ -138,3 +140,7 @@ func (c *MetalStackCluster) GetConditions() clusterv1.Conditions { func (c *MetalStackCluster) SetConditions(conditions clusterv1.Conditions) { c.Status.Conditions = conditions } + +func (c *MetalStackCluster) GetClusterID() string { + return fmt.Sprintf("%s/%s", c.GetNamespace(), c.GetName()) +} diff --git a/config/target-cluster/metal-ccm.yaml b/config/target-cluster/metal-ccm.yaml new file mode 100644 index 0000000..85c28fd --- /dev/null +++ b/config/target-cluster/metal-ccm.yaml @@ -0,0 +1,230 @@ +--- +apiVersion: v1 +kind: Secret +metadata: + name: cloud-controller-manager + namespace: kube-system +stringData: + api-url: ${METAL_API_URL} + api-hmac: ${METAL_API_HMAC} + api-hmac-auth-type: ${METAL_API_HMAC_AUTH_TYPE} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: cloud-controller-manager + namespace: kube-system +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: cloud-controller-manager +rules: + - apiGroups: + - "" + resources: + - events + verbs: + - create + - patch + - update + - apiGroups: + - "" + resources: + - nodes + verbs: + - "*" + - apiGroups: + - "" + resources: + - nodes/status + verbs: + - patch + - apiGroups: + - "" + resources: + - services + - services/status + - endpoints + verbs: + - get + - list + - patch + - update + - watch + - apiGroups: + - "" + resources: + - serviceaccounts + - serviceaccounts/token + verbs: + - create + - get + - list + - watch + - apiGroups: + - "" + resources: + - secrets + - configmaps + verbs: + - get + - list + - watch + - update + - create + - patch + - delete + - apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - get + - create + - update + - apiGroups: + - metallb.io + resources: + - bgppeers + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + - apiGroups: + - metallb.io + resources: + - ipaddresspools + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + - apiGroups: + - metallb.io + resources: + - bgpadvertisements + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: cloud-controller-manager +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: cloud-controller-manager +subjects: + - kind: ServiceAccount + name: cloud-controller-manager + namespace: kube-system +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: cloud-controller-manager + name: cloud-controller-manager + namespace: kube-system +spec: + replicas: 1 + selector: + matchLabels: + app: cloud-controller-manager + strategy: + type: RollingUpdate + template: + metadata: + labels: + app: cloud-controller-manager + spec: + containers: + - command: + - ./metal-cloud-controller-manager + - --cluster-cidr=10.240.0.0/12 + - --cluster-name= + - --concurrent-service-syncs=10 + - --leader-elect=true + - --secure-port=10258 + - --use-service-account-credentials + - --v=2 + env: + - name: METAL_API_URL + valueFrom: + secretKeyRef: + key: api-url + name: cloud-controller-manager + - name: METAL_AUTH_HMAC + valueFrom: + secretKeyRef: + key: api-hmac + name: cloud-controller-manager + - name: METAL_AUTH_HMAC_AUTH_TYPE + valueFrom: + secretKeyRef: + key: api-hmac-auth-type + name: cloud-controller-manager + - name: METAL_PROJECT_ID + value: ${METAL_PROJECT_ID} + - name: METAL_PARTITION_ID + value: ${METAL_PARTITION} + # associates service type load balancer ips with this cluster: + - name: METAL_CLUSTER_ID + value: ${NAMESPACE}/${CLUSTER_NAME} + - name: METAL_DEFAULT_EXTERNAL_NETWORK_ID + value: internet + - name: METAL_ADDITIONAL_NETWORKS + value: internet,${METAL_NODE_NETWORK_ID} + - name: METAL_SSH_PUBLICKEY + value: "" + image: ghcr.io/metal-stack/metal-ccm:v0.9.4 + imagePullPolicy: IfNotPresent + livenessProbe: + failureThreshold: 2 + httpGet: + path: /healthz + port: 10258 + scheme: HTTPS + initialDelaySeconds: 15 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 15 + name: cloud-controller-manager + resources: + limits: + cpu: 250m + memory: 256Mi + requests: + cpu: 100m + memory: 64Mi + nodeSelector: + node-role.kubernetes.io/control-plane: "" + hostNetwork: true + serviceAccountName: cloud-controller-manager + tolerations: + - effect: NoSchedule + operator: Exists + key: node-role.kubernetes.io/control-plane + - effect: NoSchedule + key: node.cloudprovider.kubernetes.io/uninitialized + value: "true" + restartPolicy: Always + volumes: + - name: cloud-controller-manager + secret: + defaultMode: 420 + secretName: cloud-controller-manager diff --git a/internal/controller/metalstackcluster_controller.go b/internal/controller/metalstackcluster_controller.go index aacee22..c885902 100644 --- a/internal/controller/metalstackcluster_controller.go +++ b/internal/controller/metalstackcluster_controller.go @@ -216,7 +216,7 @@ func (r *clusterReconciler) ensureControlPlaneIP() (string, error) { Networkid: defaultNetwork.ID, Projectid: &r.infraCluster.Spec.ProjectID, Tags: []string{ - tag.New(tag.ClusterID, string(r.infraCluster.GetUID())), + tag.New(tag.ClusterID, r.infraCluster.GetClusterID()), v1alpha1.TagControlPlanePurpose, }, Type: ptr.To(models.V1IPBaseTypeEphemeral), diff --git a/internal/controller/metalstackcluster_controller_test.go b/internal/controller/metalstackcluster_controller_test.go index d1997b1..198af05 100644 --- a/internal/controller/metalstackcluster_controller_test.go +++ b/internal/controller/metalstackcluster_controller_test.go @@ -271,7 +271,7 @@ var _ = Describe("MetalStackCluster Controller", func() { IP: func(m *mock.Mock) { m.On("AllocateIP", testcommon.MatchIgnoreContext(testingT, metalip.NewAllocateIPParams().WithBody(&models.V1IPAllocateRequest{ Tags: []string{ - "cluster.metal-stack.io/id=" + string(resource.UID), + "cluster.metal-stack.io/id=" + resource.GetClusterID(), "metal-stack.infrastructure.cluster.x-k8s.io/purpose=control-plane", }, Name: resource.Name + "-control-plane", diff --git a/internal/controller/metalstackmachine_controller.go b/internal/controller/metalstackmachine_controller.go index ecce64b..abed6cb 100644 --- a/internal/controller/metalstackmachine_controller.go +++ b/internal/controller/metalstackmachine_controller.go @@ -317,7 +317,7 @@ func (r *machineReconciler) create() (*models.V1MachineResponse, error) { resp, err := r.metalClient.Machine().AllocateMachine(metalmachine.NewAllocateMachineParamsWithContext(r.ctx).WithBody(&models.V1MachineAllocateRequest{ Partitionid: &r.infraCluster.Spec.Partition, Projectid: &r.infraCluster.Spec.ProjectID, - PlacementTags: []string{tag.New(tag.ClusterID, string(r.infraCluster.GetUID()))}, + PlacementTags: []string{tag.New(tag.ClusterID, r.infraCluster.GetClusterID())}, Tags: append(r.machineTags(), r.additionalMachineTags()...), Name: r.infraMachine.Name, Hostname: r.infraMachine.Name, @@ -437,6 +437,7 @@ func (r *machineReconciler) patchMachineLabels(m *models.V1MachineResponse) { func (r *machineReconciler) machineTags() []string { tags := []string{ + tag.New(tag.ClusterID, r.infraCluster.Spec.NodeNetworkID), tag.New(v1alpha1.TagInfraClusterResource, fmt.Sprintf("%s/%s", r.infraCluster.Namespace, r.infraCluster.Name)), tag.New(v1alpha1.TagInfraMachineResource, fmt.Sprintf("%s/%s", r.infraMachine.Namespace, r.infraMachine.Name)), }