From 0350466568cca83ac6dc516a2b0bde1a2a75a385 Mon Sep 17 00:00:00 2001 From: Adam Janikowski <12255597+ajanikow@users.noreply.github.com> Date: Wed, 2 Feb 2022 11:56:57 +0100 Subject: [PATCH] [Feature] ARM64 Support (#900) --- CHANGELOG.md | 1 + Dockerfile | 2 +- Makefile | 10 ++- chart/kube-arangodb/README.md | 6 ++ chart/kube-arangodb/templates/deployment.yaml | 4 +- chart/kube-arangodb/values.yaml | 3 + pkg/apis/deployment/v1/architecture.go | 89 +++++++++++++++++++ pkg/apis/deployment/v1/deployment_spec.go | 8 +- .../deployment/v1/zz_generated.deepcopy.go | 25 ++++++ pkg/apis/deployment/v2alpha1/architecture.go | 89 +++++++++++++++++++ .../deployment/v2alpha1/deployment_spec.go | 8 +- .../v2alpha1/zz_generated.deepcopy.go | 25 ++++++ pkg/deployment/images.go | 2 +- pkg/deployment/pod/affinity.go | 13 +-- .../resources/pod_creator_arangod.go | 2 +- pkg/deployment/resources/pod_creator_sync.go | 2 +- 16 files changed, 269 insertions(+), 20 deletions(-) create mode 100644 pkg/apis/deployment/v1/architecture.go create mode 100644 pkg/apis/deployment/v2alpha1/architecture.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 443edc8cc..ce895eb47 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ - Add status.members.. - Define MemberReplacementRequired condition - Remove pod immediately when annotation is turned on +- (ARM64) Add support for ARM64 enablement ## [1.2.7](https://github.com/arangodb/kube-arangodb/tree/1.2.7) (2022-01-17) - Add Plan BackOff functionality diff --git a/Dockerfile b/Dockerfile index 46c900d7c..095e7c5fe 100644 --- a/Dockerfile +++ b/Dockerfile @@ -13,7 +13,7 @@ LABEL name="kube-arangodb" \ ADD ./LICENSE /licenses/LICENSE ARG RELEASE_MODE=community -ARG TARGETARCH=amd64 +ARG TARGETARCH ADD bin/${RELEASE_MODE}/linux/${TARGETARCH}/arangodb_operator /usr/bin/arangodb_operator ENTRYPOINT [ "/usr/bin/arangodb_operator" ] diff --git a/Makefile b/Makefile index 329a693a6..23d072a49 100644 --- a/Makefile +++ b/Makefile @@ -31,7 +31,11 @@ REPOPATH := $(ORGPATH)/$(REPONAME) include $(ROOT)/$(RELEASE_MODE).mk -GOPATH := $(GOBUILDDIR) +ifndef KEEP_GOPATH + GOPATH := $(GOBUILDDIR) +endif + +GOBUILDARGS ?= GOVERSION := 1.17-alpine3.15 DISTRIBUTION := alpine:3.15 @@ -272,11 +276,11 @@ bin-all: $(BIN) $(VBIN_LINUX_AMD64) $(VBIN_LINUX_ARM64) $(VBIN_LINUX_AMD64): $(SOURCES) dashboard/assets.go VERSION @mkdir -p $(BINDIR)/$(RELEASE_MODE)/linux/amd64 - CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build --tags "$(RELEASE_MODE)" $(COMPILE_DEBUG_FLAGS) -installsuffix netgo -ldflags "-X $(REPOPATH)/pkg/version.version=$(VERSION) -X $(REPOPATH)/pkg/version.buildDate=$(BUILDTIME) -X $(REPOPATH)/pkg/version.build=$(COMMIT)" -o $(VBIN_LINUX_AMD64) ./ + CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build ${GOBUILDARGS} --tags "$(RELEASE_MODE)" $(COMPILE_DEBUG_FLAGS) -installsuffix netgo -ldflags "-X $(REPOPATH)/pkg/version.version=$(VERSION) -X $(REPOPATH)/pkg/version.buildDate=$(BUILDTIME) -X $(REPOPATH)/pkg/version.build=$(COMMIT)" -o $(VBIN_LINUX_AMD64) ./ $(VBIN_LINUX_ARM64): $(SOURCES) dashboard/assets.go VERSION @mkdir -p $(BINDIR)/$(RELEASE_MODE)/linux/arm64 - CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build --tags "$(RELEASE_MODE)" $(COMPILE_DEBUG_FLAGS) -installsuffix netgo -ldflags "-X $(REPOPATH)/pkg/version.version=$(VERSION) -X $(REPOPATH)/pkg/version.buildDate=$(BUILDTIME) -X $(REPOPATH)/pkg/version.build=$(COMMIT)" -o $(VBIN_LINUX_ARM64) ./ + CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build ${GOBUILDARGS} --tags "$(RELEASE_MODE)" $(COMPILE_DEBUG_FLAGS) -installsuffix netgo -ldflags "-X $(REPOPATH)/pkg/version.version=$(VERSION) -X $(REPOPATH)/pkg/version.buildDate=$(BUILDTIME) -X $(REPOPATH)/pkg/version.build=$(COMMIT)" -o $(VBIN_LINUX_ARM64) ./ $(BIN): $(VBIN_LINUX_AMD64) @cp "$(VBIN_LINUX_AMD64)" "$(BIN)" diff --git a/chart/kube-arangodb/README.md b/chart/kube-arangodb/README.md index 78acc4c88..eb17d257b 100644 --- a/chart/kube-arangodb/README.md +++ b/chart/kube-arangodb/README.md @@ -193,6 +193,12 @@ Define if RBAC should be enabled. Default: `true` +### `operator.architectures` + +List of supported architectures. + +Default: `[]string{"amd64"}` + # Limitations N/A \ No newline at end of file diff --git a/chart/kube-arangodb/templates/deployment.yaml b/chart/kube-arangodb/templates/deployment.yaml index a1f213395..ff09c9324 100644 --- a/chart/kube-arangodb/templates/deployment.yaml +++ b/chart/kube-arangodb/templates/deployment.yaml @@ -63,7 +63,9 @@ spec: - key: beta.kubernetes.io/arch operator: In values: - - amd64 +{{- range .Values.operator.architectures }} + - {{ . | quote }} +{{- end }} podAntiAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 100 diff --git a/chart/kube-arangodb/values.yaml b/chart/kube-arangodb/values.yaml index 3d22cbf42..3a1a90729 100644 --- a/chart/kube-arangodb/values.yaml +++ b/chart/kube-arangodb/values.yaml @@ -6,6 +6,9 @@ operator: imagePullSecrets: [] scope: legacy + + architectures: + - amd64 debug: false diff --git a/pkg/apis/deployment/v1/architecture.go b/pkg/apis/deployment/v1/architecture.go new file mode 100644 index 000000000..21911c70d --- /dev/null +++ b/pkg/apis/deployment/v1/architecture.go @@ -0,0 +1,89 @@ +// +// DISCLAIMER +// +// Copyright 2016-2022 ArangoDB GmbH, Cologne, Germany +// +// 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. +// +// Copyright holder is ArangoDB GmbH, Cologne, Germany +// + +package v1 + +import ( + "runtime" + + "github.com/arangodb/kube-arangodb/pkg/util/k8sutil" + "github.com/pkg/errors" + core "k8s.io/api/core/v1" +) + +type ArangoDeploymentArchitecture []ArangoDeploymentArchitectureType + +func (a ArangoDeploymentArchitecture) GetDefault() ArangoDeploymentArchitectureType { + if len(a) == 0 { + return ArangoDeploymentArchitectureDefault + } + + return a[0] +} + +func (a ArangoDeploymentArchitecture) Validate() error { + if len(a) > 1 { + return errors.Errorf("Only one architecture type is supported currently") + } + + for id := range a { + if err := a[id].Validate(); err != nil { + return errors.WithStack(errors.Wrapf(err, "%d", id)) + } + } + + return nil +} + +func (a ArangoDeploymentArchitecture) AsNodeSelectorRequirement() core.NodeSelectorTerm { + return core.NodeSelectorTerm{ + MatchExpressions: []core.NodeSelectorRequirement{ + { + Key: k8sutil.NodeArchAffinityLabel, + Operator: "In", + Values: []string{string(a.GetDefault())}, + }, + }, + } +} + +type ArangoDeploymentArchitectureType string + +const ( + // ArangoDeploymentArchitectureAMD64 define const for architecture for amd64 + ArangoDeploymentArchitectureAMD64 ArangoDeploymentArchitectureType = "amd64" + // ArangoDeploymentArchitectureARM64 define const for architecture for arm64 + ArangoDeploymentArchitectureARM64 ArangoDeploymentArchitectureType = "arm64" + + // ArangoDeploymentArchitectureDefault define default architecture used by Operator + ArangoDeploymentArchitectureDefault = ArangoDeploymentArchitectureAMD64 + + // ArangoDeploymentArchitectureCurrent define current Operator architecture + ArangoDeploymentArchitectureCurrent = ArangoDeploymentArchitectureType(runtime.GOARCH) +) + +func (a ArangoDeploymentArchitectureType) Validate() error { + switch q := a; q { + case ArangoDeploymentArchitectureAMD64, ArangoDeploymentArchitectureARM64: + return nil + default: + return errors.Errorf("Unknown architecture type %s", q) + } +} diff --git a/pkg/apis/deployment/v1/deployment_spec.go b/pkg/apis/deployment/v1/deployment_spec.go index a2e9135de..ce6868a2b 100644 --- a/pkg/apis/deployment/v1/deployment_spec.go +++ b/pkg/apis/deployment/v1/deployment_spec.go @@ -83,7 +83,7 @@ const ( DeploymentCommunicationMethodHeadlessService DeploymentCommunicationMethod = "headless" // DeploymentCommunicationMethodDNS define ClusterIP Service DNS based communication. DeploymentCommunicationMethodDNS DeploymentCommunicationMethod = "dns" - // DeploymentCommunicationMethodDNS define ClusterIP Service DNS based communication. Use namespaced short DNS (used in migration) + // DeploymentCommunicationMethodShortDNS define ClusterIP Service DNS based communication. Use namespaced short DNS (used in migration) DeploymentCommunicationMethodShortDNS DeploymentCommunicationMethod = "short-dns" // DeploymentCommunicationMethodIP define ClusterIP Servce IP based communication. DeploymentCommunicationMethodIP DeploymentCommunicationMethod = "ip" @@ -168,6 +168,9 @@ type DeploymentSpec struct { // Rebalancer define the rebalancer specification Rebalancer *ArangoDeploymentRebalancerSpec `json:"rebalancer,omitempty"` + + // Architecture definition of supported architectures + Architecture ArangoDeploymentArchitecture `json:"architecture,omitempty"` } // GetAllowMemberRecreation returns member recreation policy based on group and settings @@ -461,6 +464,9 @@ func (s *DeploymentSpec) Validate() error { if err := s.Bootstrap.Validate(); err != nil { return errors.WithStack(err) } + if err := s.Architecture.Validate(); err != nil { + return errors.WithStack(errors.Wrap(err, "spec.architecture")) + } return nil } diff --git a/pkg/apis/deployment/v1/zz_generated.deepcopy.go b/pkg/apis/deployment/v1/zz_generated.deepcopy.go index 81ca5cd2b..bcb776426 100644 --- a/pkg/apis/deployment/v1/zz_generated.deepcopy.go +++ b/pkg/apis/deployment/v1/zz_generated.deepcopy.go @@ -183,6 +183,26 @@ func (in *ArangoDeployment) DeepCopyObject() runtime.Object { return nil } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in ArangoDeploymentArchitecture) DeepCopyInto(out *ArangoDeploymentArchitecture) { + { + in := &in + *out = make(ArangoDeploymentArchitecture, len(*in)) + copy(*out, *in) + return + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ArangoDeploymentArchitecture. +func (in ArangoDeploymentArchitecture) DeepCopy() ArangoDeploymentArchitecture { + if in == nil { + return nil + } + out := new(ArangoDeploymentArchitecture) + in.DeepCopyInto(out) + return *out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ArangoDeploymentList) DeepCopyInto(out *ArangoDeploymentList) { *out = *in @@ -844,6 +864,11 @@ func (in *DeploymentSpec) DeepCopyInto(out *DeploymentSpec) { *out = new(ArangoDeploymentRebalancerSpec) (*in).DeepCopyInto(*out) } + if in.Architecture != nil { + in, out := &in.Architecture, &out.Architecture + *out = make(ArangoDeploymentArchitecture, len(*in)) + copy(*out, *in) + } return } diff --git a/pkg/apis/deployment/v2alpha1/architecture.go b/pkg/apis/deployment/v2alpha1/architecture.go new file mode 100644 index 000000000..a228129b9 --- /dev/null +++ b/pkg/apis/deployment/v2alpha1/architecture.go @@ -0,0 +1,89 @@ +// +// DISCLAIMER +// +// Copyright 2016-2022 ArangoDB GmbH, Cologne, Germany +// +// 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. +// +// Copyright holder is ArangoDB GmbH, Cologne, Germany +// + +package v2alpha1 + +import ( + "runtime" + + "github.com/arangodb/kube-arangodb/pkg/util/k8sutil" + "github.com/pkg/errors" + core "k8s.io/api/core/v1" +) + +type ArangoDeploymentArchitecture []ArangoDeploymentArchitectureType + +func (a ArangoDeploymentArchitecture) GetDefault() ArangoDeploymentArchitectureType { + if len(a) == 0 { + return ArangoDeploymentArchitectureDefault + } + + return a[0] +} + +func (a ArangoDeploymentArchitecture) Validate() error { + if len(a) > 1 { + return errors.Errorf("Only one architecture type is supported currently") + } + + for id := range a { + if err := a[id].Validate(); err != nil { + return errors.WithStack(errors.Wrapf(err, "%d", id)) + } + } + + return nil +} + +func (a ArangoDeploymentArchitecture) AsNodeSelectorRequirement() core.NodeSelectorTerm { + return core.NodeSelectorTerm{ + MatchExpressions: []core.NodeSelectorRequirement{ + { + Key: k8sutil.NodeArchAffinityLabel, + Operator: "In", + Values: []string{string(a.GetDefault())}, + }, + }, + } +} + +type ArangoDeploymentArchitectureType string + +const ( + // ArangoDeploymentArchitectureAMD64 define const for architecture for amd64 + ArangoDeploymentArchitectureAMD64 ArangoDeploymentArchitectureType = "amd64" + // ArangoDeploymentArchitectureARM64 define const for architecture for arm64 + ArangoDeploymentArchitectureARM64 ArangoDeploymentArchitectureType = "arm64" + + // ArangoDeploymentArchitectureDefault define default architecture used by Operator + ArangoDeploymentArchitectureDefault = ArangoDeploymentArchitectureAMD64 + + // ArangoDeploymentArchitectureCurrent define current Operator architecture + ArangoDeploymentArchitectureCurrent = ArangoDeploymentArchitectureType(runtime.GOARCH) +) + +func (a ArangoDeploymentArchitectureType) Validate() error { + switch q := a; q { + case ArangoDeploymentArchitectureAMD64, ArangoDeploymentArchitectureARM64: + return nil + default: + return errors.Errorf("Unknown architecture type %s", q) + } +} diff --git a/pkg/apis/deployment/v2alpha1/deployment_spec.go b/pkg/apis/deployment/v2alpha1/deployment_spec.go index d9254ca58..874cb361a 100644 --- a/pkg/apis/deployment/v2alpha1/deployment_spec.go +++ b/pkg/apis/deployment/v2alpha1/deployment_spec.go @@ -83,7 +83,7 @@ const ( DeploymentCommunicationMethodHeadlessService DeploymentCommunicationMethod = "headless" // DeploymentCommunicationMethodDNS define ClusterIP Service DNS based communication. DeploymentCommunicationMethodDNS DeploymentCommunicationMethod = "dns" - // DeploymentCommunicationMethodDNS define ClusterIP Service DNS based communication. Use namespaced short DNS (used in migration) + // DeploymentCommunicationMethodShortDNS define ClusterIP Service DNS based communication. Use namespaced short DNS (used in migration) DeploymentCommunicationMethodShortDNS DeploymentCommunicationMethod = "short-dns" // DeploymentCommunicationMethodIP define ClusterIP Servce IP based communication. DeploymentCommunicationMethodIP DeploymentCommunicationMethod = "ip" @@ -168,6 +168,9 @@ type DeploymentSpec struct { // Rebalancer define the rebalancer specification Rebalancer *ArangoDeploymentRebalancerSpec `json:"rebalancer,omitempty"` + + // Architecture definition of supported architectures + Architecture ArangoDeploymentArchitecture `json:"architecture,omitempty"` } // GetAllowMemberRecreation returns member recreation policy based on group and settings @@ -461,6 +464,9 @@ func (s *DeploymentSpec) Validate() error { if err := s.Bootstrap.Validate(); err != nil { return errors.WithStack(err) } + if err := s.Architecture.Validate(); err != nil { + return errors.WithStack(errors.Wrap(err, "spec.architecture")) + } return nil } diff --git a/pkg/apis/deployment/v2alpha1/zz_generated.deepcopy.go b/pkg/apis/deployment/v2alpha1/zz_generated.deepcopy.go index c62dd6d5a..7049809c0 100644 --- a/pkg/apis/deployment/v2alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/deployment/v2alpha1/zz_generated.deepcopy.go @@ -183,6 +183,26 @@ func (in *ArangoDeployment) DeepCopyObject() runtime.Object { return nil } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in ArangoDeploymentArchitecture) DeepCopyInto(out *ArangoDeploymentArchitecture) { + { + in := &in + *out = make(ArangoDeploymentArchitecture, len(*in)) + copy(*out, *in) + return + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ArangoDeploymentArchitecture. +func (in ArangoDeploymentArchitecture) DeepCopy() ArangoDeploymentArchitecture { + if in == nil { + return nil + } + out := new(ArangoDeploymentArchitecture) + in.DeepCopyInto(out) + return *out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ArangoDeploymentList) DeepCopyInto(out *ArangoDeploymentList) { *out = *in @@ -844,6 +864,11 @@ func (in *DeploymentSpec) DeepCopyInto(out *DeploymentSpec) { *out = new(ArangoDeploymentRebalancerSpec) (*in).DeepCopyInto(*out) } + if in.Architecture != nil { + in, out := &in.Architecture, &out.Architecture + *out = make(ArangoDeploymentArchitecture, len(*in)) + copy(*out, *in) + } return } diff --git a/pkg/deployment/images.go b/pkg/deployment/images.go index 601d38c82..5c14e2623 100644 --- a/pkg/deployment/images.go +++ b/pkg/deployment/images.go @@ -355,7 +355,7 @@ func (i *ImageUpdatePod) GetPodAffinity() *core.PodAffinity { func (i *ImageUpdatePod) GetNodeAffinity() *core.NodeAffinity { a := core.NodeAffinity{} - pod.AppendNodeSelector(&a) + pod.AppendArchSelector(&a, i.spec.Architecture) pod.MergeNodeAffinity(&a, i.spec.ID.Get().NodeAffinity) diff --git a/pkg/deployment/pod/affinity.go b/pkg/deployment/pod/affinity.go index 33a9570d1..2d41ea848 100644 --- a/pkg/deployment/pod/affinity.go +++ b/pkg/deployment/pod/affinity.go @@ -21,6 +21,7 @@ package pod import ( + api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1" "github.com/arangodb/kube-arangodb/pkg/util/k8sutil" "github.com/arangodb/kube-arangodb/pkg/util/k8sutil/interfaces" core "k8s.io/api/core/v1" @@ -49,20 +50,12 @@ func AppendPodAntiAffinityDefault(p interfaces.PodCreator, a *core.PodAntiAffini } } -func AppendNodeSelector(a *core.NodeAffinity) { +func AppendArchSelector(a *core.NodeAffinity, arch api.ArangoDeploymentArchitecture) { if a.RequiredDuringSchedulingIgnoredDuringExecution == nil { a.RequiredDuringSchedulingIgnoredDuringExecution = &core.NodeSelector{} } - a.RequiredDuringSchedulingIgnoredDuringExecution.NodeSelectorTerms = append(a.RequiredDuringSchedulingIgnoredDuringExecution.NodeSelectorTerms, core.NodeSelectorTerm{ - MatchExpressions: []core.NodeSelectorRequirement{ - { - Key: k8sutil.NodeArchAffinityLabel, - Operator: "In", - Values: []string{"amd64"}, - }, - }, - }) + a.RequiredDuringSchedulingIgnoredDuringExecution.NodeSelectorTerms = append(a.RequiredDuringSchedulingIgnoredDuringExecution.NodeSelectorTerms, arch.AsNodeSelectorRequirement()) } func AppendAffinityWithRole(p interfaces.PodCreator, a *core.PodAffinity, role string) { diff --git a/pkg/deployment/resources/pod_creator_arangod.go b/pkg/deployment/resources/pod_creator_arangod.go index 361532b16..d0959e89e 100644 --- a/pkg/deployment/resources/pod_creator_arangod.go +++ b/pkg/deployment/resources/pod_creator_arangod.go @@ -331,7 +331,7 @@ func (m *MemberArangoDPod) GetPodAffinity() *core.PodAffinity { func (m *MemberArangoDPod) GetNodeAffinity() *core.NodeAffinity { a := core.NodeAffinity{} - pod.AppendNodeSelector(&a) + pod.AppendArchSelector(&a, m.spec.Architecture) pod.MergeNodeAffinity(&a, m.groupSpec.NodeAffinity) diff --git a/pkg/deployment/resources/pod_creator_sync.go b/pkg/deployment/resources/pod_creator_sync.go index ba9364b75..e74e254da 100644 --- a/pkg/deployment/resources/pod_creator_sync.go +++ b/pkg/deployment/resources/pod_creator_sync.go @@ -230,7 +230,7 @@ func (m *MemberSyncPod) GetPodAffinity() *core.PodAffinity { func (m *MemberSyncPod) GetNodeAffinity() *core.NodeAffinity { a := core.NodeAffinity{} - pod.AppendNodeSelector(&a) + pod.AppendArchSelector(&a, m.spec.Architecture) pod.MergeNodeAffinity(&a, m.groupSpec.NodeAffinity)