fix: ensure critical addons come up when the node is tainted
Rather than taint on `node-role.kubernetes.io/master=true:NoSchedule`, we check for `CriticalAddonsOnly=true:NoSchedule` and taint on that.
This commit is contained in:
@@ -3,6 +3,7 @@ package scheduler_k3s
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"sort"
|
||||
@@ -11,6 +12,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/dokku/dokku/plugins/common"
|
||||
"gopkg.in/yaml.v3"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
@@ -116,17 +118,6 @@ func createKubernetesNamespace(ctx context.Context, namespaceName string) error
|
||||
return err
|
||||
}
|
||||
|
||||
namespaces, err := clientset.ListNamespaces(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, namespace := range namespaces {
|
||||
if namespace.Name == namespaceName {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
namespace := corev1.Namespace{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: namespaceName,
|
||||
@@ -139,7 +130,7 @@ func createKubernetesNamespace(ctx context.Context, namespaceName string) error
|
||||
},
|
||||
}
|
||||
_, err = clientset.CreateNamespace(ctx, CreateNamespaceInput{
|
||||
Namespace: namespace,
|
||||
Name: namespace,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -322,6 +313,73 @@ func getStartCommand(input StartCommandInput) (StartCommandOutput, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
func installHelmCharts(ctx context.Context, clientset KubernetesClient) error {
|
||||
for _, repo := range HelmRepositories {
|
||||
helmAgent, err := NewHelmAgent("default", DeployLogPrinter)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error creating helm agent: %w", err)
|
||||
}
|
||||
|
||||
err = helmAgent.AddRepository(ctx, AddRepositoryInput(repo))
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error adding helm repository %s: %w", repo.Name, err)
|
||||
}
|
||||
}
|
||||
|
||||
for _, chart := range HelmCharts {
|
||||
if chart.CreateNamespace {
|
||||
namespace := corev1.Namespace{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: chart.Namespace,
|
||||
Annotations: map[string]string{
|
||||
"dokku.com/managed": "true",
|
||||
},
|
||||
Labels: map[string]string{
|
||||
"dokku.com/managed": "true",
|
||||
},
|
||||
},
|
||||
}
|
||||
_, err := clientset.CreateNamespace(ctx, CreateNamespaceInput{
|
||||
Name: namespace,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error creating namespace %s: %w", chart.Namespace, err)
|
||||
}
|
||||
}
|
||||
|
||||
contents, err := templates.ReadFile(fmt.Sprintf("templates/%s.yaml", chart.ReleaseName))
|
||||
if err != nil && !errors.Is(err, os.ErrNotExist) {
|
||||
return fmt.Errorf("Error reading values file %s: %w", chart.ReleaseName, err)
|
||||
}
|
||||
|
||||
var values map[string]interface{}
|
||||
if len(contents) > 0 {
|
||||
err = yaml.Unmarshal(contents, &values)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error unmarshalling values file: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
helmAgent, err := NewHelmAgent(chart.Namespace, DeployLogPrinter)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error creating helm agent: %w", err)
|
||||
}
|
||||
|
||||
err = helmAgent.InstallOrUpgradeChart(ctx, ChartInput{
|
||||
ChartPath: chart.ChartPath,
|
||||
Namespace: chart.Namespace,
|
||||
ReleaseName: chart.ReleaseName,
|
||||
RepoURL: chart.RepoURL,
|
||||
Values: values,
|
||||
Version: chart.Version,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error installing chart %s: %w", chart.ChartPath, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func isK3sInstalled() error {
|
||||
if !common.FileExists("/usr/local/bin/k3s") {
|
||||
return fmt.Errorf("k3s binary is not available")
|
||||
@@ -340,7 +398,7 @@ func isK3sInstalled() error {
|
||||
|
||||
func isPodReady(ctx context.Context, clientset KubernetesClient, podName, namespace string) wait.ConditionWithContextFunc {
|
||||
return func(ctx context.Context) (bool, error) {
|
||||
fmt.Printf(".") // progress bar!
|
||||
fmt.Printf(".")
|
||||
|
||||
pod, err := clientset.GetPod(ctx, GetPodInput{
|
||||
Name: podName,
|
||||
|
||||
@@ -10,6 +10,7 @@ require (
|
||||
github.com/fatih/color v1.16.0
|
||||
github.com/go-openapi/jsonpointer v0.19.6
|
||||
github.com/go-resty/resty/v2 v2.11.0
|
||||
github.com/gofrs/flock v0.8.1
|
||||
github.com/hashicorp/go-multierror v1.1.1
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
|
||||
github.com/rancher/wharfie v0.6.5
|
||||
|
||||
@@ -155,6 +155,8 @@ github.com/gobuffalo/packr/v2 v2.8.3 h1:xE1yzvnO56cUC0sTpKR3DIbxZgB54AftTFMhB2XE
|
||||
github.com/gobuffalo/packr/v2 v2.8.3/go.mod h1:0SahksCVcx4IMnigTjiFuyldmTrdTctXsOdiU5KwbKc=
|
||||
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
|
||||
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
|
||||
github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw=
|
||||
github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
|
||||
@@ -4,18 +4,23 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
"unicode"
|
||||
|
||||
"github.com/dokku/dokku/plugins/common"
|
||||
"github.com/gofrs/flock"
|
||||
"gopkg.in/yaml.v3"
|
||||
"helm.sh/helm/v3/pkg/action"
|
||||
"helm.sh/helm/v3/pkg/chart/loader"
|
||||
"helm.sh/helm/v3/pkg/cli"
|
||||
"helm.sh/helm/v3/pkg/getter"
|
||||
"helm.sh/helm/v3/pkg/kube"
|
||||
"helm.sh/helm/v3/pkg/repo"
|
||||
"helm.sh/helm/v3/pkg/storage/driver"
|
||||
)
|
||||
|
||||
@@ -43,8 +48,10 @@ type ChartInput struct {
|
||||
ChartPath string
|
||||
Namespace string
|
||||
ReleaseName string
|
||||
RepoURL string
|
||||
RollbackOnFailure bool
|
||||
Timeout time.Duration
|
||||
Version string
|
||||
Values map[string]interface{}
|
||||
}
|
||||
|
||||
@@ -80,7 +87,74 @@ func NewHelmAgent(namespace string, logger action.DebugLog) (*HelmAgent, error)
|
||||
}, nil
|
||||
}
|
||||
|
||||
type AddRepositoryInput struct {
|
||||
Name string
|
||||
URL string
|
||||
}
|
||||
|
||||
func (h *HelmAgent) AddRepository(ctx context.Context, helmRepo AddRepositoryInput) error {
|
||||
settings := cli.New()
|
||||
repoFile := settings.RepositoryConfig
|
||||
|
||||
err := os.MkdirAll(filepath.Dir(repoFile), os.ModePerm)
|
||||
if err != nil && !os.IsExist(err) {
|
||||
return fmt.Errorf("Error creating repository directory: %w", err)
|
||||
}
|
||||
|
||||
fileLock := flock.New(strings.Replace(repoFile, filepath.Ext(repoFile), ".lock", 1))
|
||||
locked, err := fileLock.TryLockContext(ctx, time.Second)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error acquiring file lock: %w", err)
|
||||
}
|
||||
|
||||
if !locked {
|
||||
return fmt.Errorf("Could not acquire file lock")
|
||||
}
|
||||
|
||||
defer fileLock.Unlock() // nolint: errcheck
|
||||
|
||||
b, err := os.ReadFile(repoFile)
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
return fmt.Errorf("Error reading repository file: %w", err)
|
||||
}
|
||||
|
||||
var f repo.File
|
||||
if err := yaml.Unmarshal(b, &f); err != nil {
|
||||
return fmt.Errorf("Error unmarshalling yaml: %w", err)
|
||||
}
|
||||
|
||||
if f.Has(helmRepo.Name) {
|
||||
return nil
|
||||
}
|
||||
|
||||
c := repo.Entry{
|
||||
Name: helmRepo.Name,
|
||||
URL: helmRepo.URL,
|
||||
}
|
||||
|
||||
r, err := repo.NewChartRepository(&c, getter.All(settings))
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error creating chart repository: %w", err)
|
||||
}
|
||||
|
||||
if _, err := r.DownloadIndexFile(); err != nil {
|
||||
return fmt.Errorf("Specified repository '%q' is not a valid chart repository or cannot be reached: %w", helmRepo.URL, err)
|
||||
}
|
||||
|
||||
f.Update(&c)
|
||||
|
||||
if err := f.WriteFile(repoFile, 0644); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *HelmAgent) ChartExists(releaseName string) (bool, error) {
|
||||
if releaseName == "" {
|
||||
return false, fmt.Errorf("Release name is required")
|
||||
}
|
||||
|
||||
client := action.NewHistory(h.Configuration)
|
||||
client.Max = 1
|
||||
releases, err := client.Run(releaseName)
|
||||
@@ -98,14 +172,14 @@ func (h *HelmAgent) ChartExists(releaseName string) (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (h *HelmAgent) DeleteRevision(releaseName string, revision int) error {
|
||||
func (h *HelmAgent) DeleteRevision(ctx context.Context, releaseName string, revision int) error {
|
||||
clientset, err := NewKubernetesClient()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error creating kubernetes client: %w", err)
|
||||
}
|
||||
|
||||
secretName := fmt.Sprintf("sh.helm.release.v1.%s.v%d", releaseName, revision)
|
||||
err = clientset.DeleteSecret(context.Background(), DeleteSecretInput{
|
||||
err = clientset.DeleteSecret(ctx, DeleteSecretInput{
|
||||
Name: secretName,
|
||||
Namespace: h.Namespace,
|
||||
})
|
||||
@@ -126,7 +200,7 @@ func (h *HelmAgent) GetValues(releaseName string) (map[string]interface{}, error
|
||||
return values, nil
|
||||
}
|
||||
|
||||
func (h *HelmAgent) InstallOrUpgradeChart(input ChartInput) error {
|
||||
func (h *HelmAgent) InstallOrUpgradeChart(ctx context.Context, input ChartInput) error {
|
||||
chartExists, err := h.ChartExists(input.ReleaseName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error checking if chart exists: %w", err)
|
||||
@@ -134,14 +208,14 @@ func (h *HelmAgent) InstallOrUpgradeChart(input ChartInput) error {
|
||||
|
||||
if chartExists {
|
||||
common.LogExclaim(fmt.Sprintf("Upgrading %s", input.ReleaseName))
|
||||
return h.UpgradeChart(input)
|
||||
return h.UpgradeChart(ctx, input)
|
||||
}
|
||||
|
||||
common.LogExclaim(fmt.Sprintf("Installing %s", input.ReleaseName))
|
||||
return h.InstallChart(input)
|
||||
return h.InstallChart(ctx, input)
|
||||
}
|
||||
|
||||
func (h *HelmAgent) InstallChart(input ChartInput) error {
|
||||
func (h *HelmAgent) InstallChart(ctx context.Context, input ChartInput) error {
|
||||
namespace := input.Namespace
|
||||
if namespace == "" {
|
||||
namespace = h.Namespace
|
||||
@@ -167,7 +241,15 @@ func (h *HelmAgent) InstallChart(input ChartInput) error {
|
||||
client.Timeout = input.Timeout
|
||||
client.Wait = false
|
||||
|
||||
chart, err := client.ChartPathOptions.LocateChart(input.ChartPath, nil)
|
||||
settings := cli.New()
|
||||
if input.RepoURL != "" {
|
||||
client.ChartPathOptions.RepoURL = input.RepoURL
|
||||
}
|
||||
if input.Version != "" {
|
||||
client.ChartPathOptions.Version = input.Version
|
||||
}
|
||||
|
||||
chart, err := client.ChartPathOptions.LocateChart(input.ChartPath, settings)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error locating chart: %w", err)
|
||||
}
|
||||
@@ -177,16 +259,6 @@ func (h *HelmAgent) InstallChart(input ChartInput) error {
|
||||
return fmt.Errorf("Error loading chart: %w", err)
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
cSignal := make(chan os.Signal, 2)
|
||||
signal.Notify(cSignal, os.Interrupt, syscall.SIGTERM)
|
||||
go func() {
|
||||
<-cSignal
|
||||
common.LogWarn(fmt.Sprintf("Deployment of %s has been cancelled", input.ReleaseName))
|
||||
cancel()
|
||||
}()
|
||||
|
||||
_, err = client.RunWithContext(ctx, chartRequested, input.Values)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error deploying: %w", err)
|
||||
@@ -195,7 +267,7 @@ func (h *HelmAgent) InstallChart(input ChartInput) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *HelmAgent) ListRevisions(releaseName string) ([]Release, error) {
|
||||
func (h *HelmAgent) ListRevisions(ctx context.Context, releaseName string) ([]Release, error) {
|
||||
client := action.NewHistory(h.Configuration)
|
||||
response, err := client.Run(releaseName)
|
||||
if err != nil {
|
||||
@@ -218,7 +290,7 @@ func (h *HelmAgent) ListRevisions(releaseName string) ([]Release, error) {
|
||||
return releases, nil
|
||||
}
|
||||
|
||||
func (h *HelmAgent) UpgradeChart(input ChartInput) error {
|
||||
func (h *HelmAgent) UpgradeChart(ctx context.Context, input ChartInput) error {
|
||||
namespace := input.Namespace
|
||||
if namespace == "" {
|
||||
namespace = h.Namespace
|
||||
@@ -243,6 +315,9 @@ func (h *HelmAgent) UpgradeChart(input ChartInput) error {
|
||||
client.Namespace = namespace
|
||||
client.Timeout = input.Timeout
|
||||
client.Wait = false
|
||||
if input.RepoURL != "" {
|
||||
client.RepoURL = input.RepoURL
|
||||
}
|
||||
|
||||
chart, err := client.ChartPathOptions.LocateChart(input.ChartPath, nil)
|
||||
if err != nil {
|
||||
@@ -254,16 +329,6 @@ func (h *HelmAgent) UpgradeChart(input ChartInput) error {
|
||||
return fmt.Errorf("Error loading chart: %w", err)
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
cSignal := make(chan os.Signal, 2)
|
||||
signal.Notify(cSignal, os.Interrupt, syscall.SIGTERM)
|
||||
go func() {
|
||||
<-cSignal
|
||||
common.LogWarn(fmt.Sprintf("Deployment of %s has been cancelled", input.ReleaseName))
|
||||
cancel()
|
||||
}()
|
||||
|
||||
_, err = client.RunWithContext(ctx, input.ReleaseName, chartRequested, input.Values)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error deploying: %w", err)
|
||||
|
||||
@@ -154,13 +154,24 @@ func (k KubernetesClient) CreateJob(ctx context.Context, input CreateJobInput) (
|
||||
|
||||
// CreateNamespaceInput contains all the information needed to create a Kubernetes namespace
|
||||
type CreateNamespaceInput struct {
|
||||
// Namespace is the Kubernetes namespace
|
||||
Namespace v1.Namespace
|
||||
// Name is the name of the Kubernetes namespace
|
||||
Name v1.Namespace
|
||||
}
|
||||
|
||||
// CreateNamespace creates a Kubernetes namespace
|
||||
func (k KubernetesClient) CreateNamespace(ctx context.Context, input CreateNamespaceInput) (v1.Namespace, error) {
|
||||
namespace, err := k.Client.CoreV1().Namespaces().Create(ctx, &input.Namespace, metav1.CreateOptions{})
|
||||
namespaces, err := k.ListNamespaces(ctx)
|
||||
if err != nil {
|
||||
return v1.Namespace{}, err
|
||||
}
|
||||
|
||||
for _, namespace := range namespaces {
|
||||
if namespace.Name == input.Name.Name {
|
||||
return namespace, nil
|
||||
}
|
||||
}
|
||||
|
||||
namespace, err := k.Client.CoreV1().Namespaces().Create(ctx, &input.Name, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
return v1.Namespace{}, err
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package scheduler_k3s
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"sync"
|
||||
|
||||
traefikv1alpha1 "github.com/traefik/traefik/v2/pkg/provider/kubernetes/crd/traefikio/v1alpha1"
|
||||
@@ -49,24 +50,70 @@ type Manifest struct {
|
||||
Path string
|
||||
}
|
||||
|
||||
var Manifests = []Manifest{
|
||||
{
|
||||
Name: "longhorn",
|
||||
Version: "1.5.3",
|
||||
Path: "https://raw.githubusercontent.com/longhorn/longhorn/v1.5.3/deploy/longhorn.yaml",
|
||||
},
|
||||
var KubernetesManifests = []Manifest{
|
||||
{
|
||||
Name: "system-upgrader",
|
||||
Version: "0.13.2",
|
||||
Path: "https://github.com/rancher/system-upgrade-controller/releases/v0.13.2/download/system-upgrade-controller.yaml",
|
||||
},
|
||||
{
|
||||
Name: "cert-manager",
|
||||
Version: "v1.13.3",
|
||||
Path: "https://github.com/cert-manager/cert-manager/releases/download/v1.13.3/cert-manager.yaml",
|
||||
Path: "https://github.com/rancher/system-upgrade-controller/releases/download/v0.13.2/system-upgrade-controller.yaml",
|
||||
},
|
||||
}
|
||||
|
||||
type HelmChart struct {
|
||||
ReleaseName string
|
||||
ChartPath string
|
||||
Namespace string
|
||||
CreateNamespace bool
|
||||
Version string
|
||||
Path string
|
||||
RepoURL string
|
||||
}
|
||||
|
||||
var HelmCharts = []HelmChart{
|
||||
{
|
||||
ChartPath: "cert-manager",
|
||||
CreateNamespace: true,
|
||||
Namespace: "cert-manager",
|
||||
ReleaseName: "cert-manager",
|
||||
RepoURL: "https://charts.jetstack.io",
|
||||
Version: "v1.13.3",
|
||||
},
|
||||
{
|
||||
ChartPath: "longhorn",
|
||||
CreateNamespace: true,
|
||||
Namespace: "longhorn-system",
|
||||
ReleaseName: "longhorn",
|
||||
RepoURL: "https://charts.longhorn.io",
|
||||
Version: "1.5.3",
|
||||
},
|
||||
}
|
||||
|
||||
type HelmRepository struct {
|
||||
Name string
|
||||
URL string
|
||||
}
|
||||
|
||||
var HelmRepositories = []HelmRepository{
|
||||
{
|
||||
Name: "jetstack",
|
||||
URL: "https://charts.jetstack.io",
|
||||
},
|
||||
{
|
||||
Name: "longhorn",
|
||||
URL: "https://charts.longhorn.io",
|
||||
},
|
||||
}
|
||||
|
||||
var ServerLabels = map[string]string{
|
||||
"svccontroller.k3s.cattle.io/enablelb": "true",
|
||||
}
|
||||
|
||||
var WorkerLabels = map[string]string{
|
||||
"node-role.kubernetes.io/role": "worker",
|
||||
}
|
||||
|
||||
//go:embed templates/*
|
||||
var templates embed.FS
|
||||
|
||||
func init() {
|
||||
k8sNativeSchemeOnce.Do(func() {
|
||||
_ = appsv1.AddToScheme(runtimeScheme)
|
||||
|
||||
@@ -8,7 +8,9 @@ import (
|
||||
"net"
|
||||
"net/url"
|
||||
"os"
|
||||
"os/signal"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/dokku/dokku/plugins/common"
|
||||
resty "github.com/go-resty/resty/v2"
|
||||
@@ -21,6 +23,17 @@ func CommandInitialize(taintScheduling bool) error {
|
||||
return fmt.Errorf("k3s already installed, cannot re-initialize k3s")
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
signals := make(chan os.Signal, 1)
|
||||
signal.Notify(signals, os.Interrupt, syscall.SIGHUP,
|
||||
syscall.SIGINT,
|
||||
syscall.SIGQUIT,
|
||||
syscall.SIGTERM)
|
||||
go func() {
|
||||
<-signals
|
||||
cancel()
|
||||
}()
|
||||
|
||||
networkInterface := common.PropertyGetDefault("scheduler-k3s", "--global", "network-interface", "eth0")
|
||||
ifaces, err := net.Interfaces()
|
||||
if err != nil {
|
||||
@@ -176,7 +189,7 @@ func CommandInitialize(taintScheduling bool) error {
|
||||
"--token", token,
|
||||
}
|
||||
if taintScheduling {
|
||||
args = append(args, "--node-taint", "node-role.kubernetes.io/master=true:NoSchedule")
|
||||
args = append(args, "--node-taint", "CriticalAddonsOnly=true:NoSchedule")
|
||||
}
|
||||
|
||||
common.LogInfo2Quiet("Running k3s installer")
|
||||
@@ -214,9 +227,13 @@ func CommandInitialize(taintScheduling bool) error {
|
||||
}
|
||||
|
||||
clientset, err := NewKubernetesClient()
|
||||
for _, manifest := range Manifests {
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to create kubernetes client: %w", err)
|
||||
}
|
||||
|
||||
for _, manifest := range KubernetesManifests {
|
||||
common.LogInfo2Quiet(fmt.Sprintf("Installing %s@%s", manifest.Name, manifest.Version))
|
||||
err = clientset.ApplyKubernetesManifest(context.Background(), ApplyKubernetesManifestInput{
|
||||
err = clientset.ApplyKubernetesManifest(ctx, ApplyKubernetesManifestInput{
|
||||
Manifest: manifest.Path,
|
||||
})
|
||||
if err != nil {
|
||||
@@ -224,18 +241,37 @@ func CommandInitialize(taintScheduling bool) error {
|
||||
}
|
||||
}
|
||||
|
||||
common.LogInfo2Quiet("Labeling node svccontroller.k3s.cattle.io/enablelb=true")
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to create kubernetes client: %w", err)
|
||||
for key, value := range ServerLabels {
|
||||
common.LogInfo2Quiet(fmt.Sprintf("Labeling node %s=%s", key, value))
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to create kubernetes client: %w", err)
|
||||
}
|
||||
|
||||
err = clientset.LabelNode(context.Background(), LabelNodeInput{
|
||||
Name: nodeName,
|
||||
Key: key,
|
||||
Value: value,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to patch node: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
err = clientset.LabelNode(context.Background(), LabelNodeInput{
|
||||
Name: nodeName,
|
||||
Key: "svccontroller.k3s.cattle.io/enablelb",
|
||||
Value: "true",
|
||||
})
|
||||
common.LogInfo2Quiet("Updating traefik config")
|
||||
contents, err := templates.ReadFile("templates/traefik-config.yaml")
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to patch node: %w", err)
|
||||
return fmt.Errorf("Unable to read traefik config template: %w", err)
|
||||
}
|
||||
|
||||
err = os.WriteFile("/var/lib/rancher/k3s/server/manifests/traefik-custom.yaml", contents, 0600)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to write traefik config: %w", err)
|
||||
}
|
||||
|
||||
common.LogInfo2Quiet("Installing helm charts")
|
||||
err = installHelmCharts(ctx, clientset)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to install helm charts: %w", err)
|
||||
}
|
||||
|
||||
common.LogVerboseQuiet("Done")
|
||||
@@ -449,8 +485,9 @@ func CommandClusterAdd(role string, remoteHost string, allowUknownHosts bool, ta
|
||||
// bind proxy metrics to all interfaces
|
||||
args = append(args, "--kube-proxy-arg", "metrics-bind-address=0.0.0.0")
|
||||
}
|
||||
|
||||
if taintScheduling {
|
||||
args = append(args, "--node-taint", "node-role.kubernetes.io/master=true:NoSchedule")
|
||||
args = append(args, "--node-taint", "CriticalAddonsOnly=true:NoSchedule")
|
||||
}
|
||||
|
||||
common.LogInfo2Quiet(fmt.Sprintf("Adding %s k3s cluster", nodeName))
|
||||
@@ -492,22 +529,21 @@ func CommandClusterAdd(role string, remoteHost string, allowUknownHosts bool, ta
|
||||
return fmt.Errorf("Error copying registries.yaml to remote host: %w", err)
|
||||
}
|
||||
|
||||
labels := ServerLabels
|
||||
if role == "worker" {
|
||||
common.LogInfo2Quiet("Labeling node kubernetes.io/role=worker")
|
||||
err = clientset.LabelNode(ctx, LabelNodeInput{
|
||||
Name: nodes[0].Name,
|
||||
Key: "kubernetes.io/role",
|
||||
Value: "worker",
|
||||
})
|
||||
labels = WorkerLabels
|
||||
}
|
||||
|
||||
for key, value := range labels {
|
||||
common.LogInfo2Quiet(fmt.Sprintf("Labeling node %s=%s", key, value))
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to patch node: %w", err)
|
||||
return fmt.Errorf("Unable to create kubernetes client: %w", err)
|
||||
}
|
||||
} else {
|
||||
common.LogInfo2Quiet("Labeling node svccontroller.k3s.cattle.io/enablelb=true")
|
||||
err = clientset.LabelNode(ctx, LabelNodeInput{
|
||||
Name: nodes[0].Name,
|
||||
Key: "svccontroller.k3s.cattle.io/enablelb",
|
||||
Value: "true",
|
||||
|
||||
err = clientset.LabelNode(context.Background(), LabelNodeInput{
|
||||
Name: nodeName,
|
||||
Key: key,
|
||||
Value: value,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to patch node: %w", err)
|
||||
|
||||
28
plugins/scheduler-k3s/templates/cert-manager.yaml
Normal file
28
plugins/scheduler-k3s/templates/cert-manager.yaml
Normal file
@@ -0,0 +1,28 @@
|
||||
installCRDs: true
|
||||
|
||||
tolerations:
|
||||
- key: CriticalAddonsOnly
|
||||
operator: Equal
|
||||
value: "true"
|
||||
effect: "NoSchedule"
|
||||
|
||||
webhook:
|
||||
tolerations:
|
||||
- key: CriticalAddonsOnly
|
||||
operator: Equal
|
||||
value: "true"
|
||||
effect: "NoSchedule"
|
||||
|
||||
cainjector:
|
||||
tolerations:
|
||||
- key: CriticalAddonsOnly
|
||||
operator: Equal
|
||||
value: "true"
|
||||
effect: "NoSchedule"
|
||||
|
||||
startupapicheck:
|
||||
tolerations:
|
||||
- key: CriticalAddonsOnly
|
||||
operator: Equal
|
||||
value: "true"
|
||||
effect: "NoSchedule"
|
||||
41
plugins/scheduler-k3s/templates/longhorn.yaml
Normal file
41
plugins/scheduler-k3s/templates/longhorn.yaml
Normal file
@@ -0,0 +1,41 @@
|
||||
defaultSettings:
|
||||
taintToleration: "CriticalAddonsOnly=true:NoSchedule"
|
||||
|
||||
longhornManager:
|
||||
tolerations:
|
||||
- key: CriticalAddonsOnly
|
||||
operator: Equal
|
||||
value: "true"
|
||||
effect: "NoSchedule"
|
||||
|
||||
longhornDriver:
|
||||
tolerations:
|
||||
- key: CriticalAddonsOnly
|
||||
operator: Equal
|
||||
value: "true"
|
||||
effect: "NoSchedule"
|
||||
|
||||
longhornUI:
|
||||
tolerations:
|
||||
- key: CriticalAddonsOnly
|
||||
operator: Equal
|
||||
value: "true"
|
||||
effect: "NoSchedule"
|
||||
|
||||
longhornConversionWebhook:
|
||||
- key: CriticalAddonsOnly
|
||||
operator: Equal
|
||||
value: "true"
|
||||
effect: "NoSchedule"
|
||||
|
||||
longhornAdmissionWebhook:
|
||||
- key: CriticalAddonsOnly
|
||||
operator: Equal
|
||||
value: "true"
|
||||
effect: "NoSchedule"
|
||||
|
||||
longhornRecoveryBackend:
|
||||
- key: CriticalAddonsOnly
|
||||
operator: Equal
|
||||
value: "true"
|
||||
effect: "NoSchedule"
|
||||
16
plugins/scheduler-k3s/templates/traefik-config.yaml
Normal file
16
plugins/scheduler-k3s/templates/traefik-config.yaml
Normal file
@@ -0,0 +1,16 @@
|
||||
---
|
||||
apiVersion: helm.cattle.io/v1
|
||||
kind: HelmChart
|
||||
metadata:
|
||||
name: traefik-crd
|
||||
namespace: kube-system
|
||||
spec:
|
||||
bootstrap: true
|
||||
---
|
||||
apiVersion: helm.cattle.io/v1
|
||||
kind: HelmChart
|
||||
metadata:
|
||||
name: traefik
|
||||
namespace: kube-system
|
||||
spec:
|
||||
bootstrap: true
|
||||
@@ -167,6 +167,15 @@ func TriggerSchedulerDeploy(scheduler string, appName string, imageTag string) e
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
cSignal := make(chan os.Signal, 2)
|
||||
signal.Notify(cSignal, os.Interrupt, syscall.SIGTERM)
|
||||
go func() {
|
||||
<-cSignal
|
||||
common.LogWarn(fmt.Sprintf("Deployment of %s has been cancelled", appName))
|
||||
cancel()
|
||||
}()
|
||||
|
||||
namespace := common.PropertyGetDefault("scheduler-k3s", appName, "namespace", "default")
|
||||
if err := createKubernetesNamespace(ctx, namespace); err != nil {
|
||||
return fmt.Errorf("Error creating kubernetes namespace for deployment: %w", err)
|
||||
@@ -455,7 +464,7 @@ data:
|
||||
return fmt.Errorf("Error parsing deploy timeout duration: %w", err)
|
||||
}
|
||||
|
||||
err = helmAgent.InstallOrUpgradeChart(ChartInput{
|
||||
err = helmAgent.InstallOrUpgradeChart(ctx, ChartInput{
|
||||
ChartPath: chartPath,
|
||||
Namespace: namespace,
|
||||
ReleaseName: fmt.Sprintf("dokku-%s", appName),
|
||||
|
||||
Reference in New Issue
Block a user