From f9e3c4ce485fda92a5d47d5ea5de8269dda24c70 Mon Sep 17 00:00:00 2001 From: divolgin Date: Tue, 30 Mar 2021 21:48:35 +0000 Subject: [PATCH] postgres 10.16 based on alpine image --- .github/workflows/kotsadm.yaml | 2 +- migrations/Makefile | 2 +- migrations/fixtures/deploy/Dockerfile | 2 +- .../kustomize/overlays/dev/postgres.yaml | 6 +-- pkg/kotsadm/configmaps.go | 18 +++++++++ pkg/kotsadm/objects/configmaps_objects.go | 24 +++++++++++ pkg/kotsadm/objects/postgres_objects.go | 25 +++++++++++- pkg/kotsadm/postgres.go | 40 +++++++++++++++---- pkg/kotsadm/secrets.go | 2 +- 9 files changed, 105 insertions(+), 16 deletions(-) diff --git a/.github/workflows/kotsadm.yaml b/.github/workflows/kotsadm.yaml index 871643dbaa..ea8c382599 100644 --- a/.github/workflows/kotsadm.yaml +++ b/.github/workflows/kotsadm.yaml @@ -634,7 +634,7 @@ jobs: id: scan uses: anchore/scan-action@v2 with: - image: "postgres:10.7" + image: "postgres:10.16-alpine" fail-build: false acs-report-enable: true severity-cutoff: high diff --git a/migrations/Makefile b/migrations/Makefile index 7fdc93755d..e0c3a46056 100644 --- a/migrations/Makefile +++ b/migrations/Makefile @@ -11,7 +11,7 @@ schema-release: build_schema mkdir -p bin/docker-archive/${PROJECT_NAME} skopeo copy docker-daemon:kotsadm/${PROJECT_NAME}:${GIT_TAG} docker-archive:bin/docker-archive/${PROJECT_NAME}/${GIT_TAG} mkdir -p bin/docker-archive/postgres - skopeo copy docker://postgres:10.7 docker-archive:bin/docker-archive/postgres/${GIT_TAG} + skopeo copy docker://postgres:10.16-alpine docker-archive:bin/docker-archive/postgres/${GIT_TAG} build_schema: docker build --pull -f deploy/Dockerfile -t ${IMAGE} . diff --git a/migrations/fixtures/deploy/Dockerfile b/migrations/fixtures/deploy/Dockerfile index 7e33593216..1409241335 100644 --- a/migrations/fixtures/deploy/Dockerfile +++ b/migrations/fixtures/deploy/Dockerfile @@ -1,4 +1,4 @@ -FROM postgres:10.7 +FROM postgres:10.16-alpine ENV POSTGRES_USER=kotsadm ENV POSTGRES_PASSWORD=password diff --git a/migrations/kustomize/overlays/dev/postgres.yaml b/migrations/kustomize/overlays/dev/postgres.yaml index a255362394..38e9b6dc53 100644 --- a/migrations/kustomize/overlays/dev/postgres.yaml +++ b/migrations/kustomize/overlays/dev/postgres.yaml @@ -41,11 +41,11 @@ spec: app: kotsadm-postgres spec: securityContext: - runAsUser: 999 # the default 'postgres' user - fsGroup: 999 + runAsUser: 70 # the default 'postgres' user + fsGroup: 70 containers: - name: postgres - image: postgres:10.7 + image: postgres:10.16-alpine imagePullPolicy: IfNotPresent env: - name: PGDATA diff --git a/pkg/kotsadm/configmaps.go b/pkg/kotsadm/configmaps.go index 10f1e56826..26dd557743 100644 --- a/pkg/kotsadm/configmaps.go +++ b/pkg/kotsadm/configmaps.go @@ -59,6 +59,24 @@ func ensureConfigMaps(deployOptions types.DeployOptions, clientset *kubernetes.C return nil } +func ensurePostgresConfigMap(deployOptions types.DeployOptions, clientset *kubernetes.Clientset) error { + _, err := clientset.CoreV1().ConfigMaps(deployOptions.Namespace).Get(context.TODO(), "kotsadm-postgres", metav1.GetOptions{}) + if err == nil { + return nil + } + + if !kuberneteserrors.IsNotFound(err) { + return errors.Wrap(err, "failed to get postgres configmap") + } + + _, err = clientset.CoreV1().ConfigMaps(deployOptions.Namespace).Create(context.TODO(), kotsadmobjects.PostgresConfigMap(deployOptions), metav1.CreateOptions{}) + if err != nil { + return errors.Wrap(err, "failed to create postgres configmap") + } + + return nil +} + func ensureWaitForAirgapConfig(deployOptions types.DeployOptions, clientset *kubernetes.Clientset, configMapName string) error { additionalLabels := map[string]string{ "kots.io/automation": "airgap", diff --git a/pkg/kotsadm/objects/configmaps_objects.go b/pkg/kotsadm/objects/configmaps_objects.go index 1629c1f88e..7d31f2c4c5 100644 --- a/pkg/kotsadm/objects/configmaps_objects.go +++ b/pkg/kotsadm/objects/configmaps_objects.go @@ -33,3 +33,27 @@ func KotsadmConfigMap(deployOptions types.DeployOptions) *corev1.ConfigMap { return configMap } + +func PostgresConfigMap(deployOptions types.DeployOptions) *corev1.ConfigMap { + // Old stretch based image used uid 999, but new alpine based image uses uid 70. + // UID remapping is needed to allow alpine image access files created by older versions. + data := map[string]string{ + "passwd": `root:x:0:0:root:/root:/bin/ash +postgres:x:999:999:Linux User,,,:/var/lib/postgresql:/bin/sh`, + } + + configMap := &corev1.ConfigMap{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "v1", + Kind: "ConfigMap", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "kotsadm-postgres", + Namespace: deployOptions.Namespace, + Labels: types.GetKotsadmLabels(), + }, + Data: data, + } + + return configMap +} diff --git a/pkg/kotsadm/objects/postgres_objects.go b/pkg/kotsadm/objects/postgres_objects.go index bb5060d08d..5d8b09c904 100644 --- a/pkg/kotsadm/objects/postgres_objects.go +++ b/pkg/kotsadm/objects/postgres_objects.go @@ -14,7 +14,7 @@ import ( ) func PostgresStatefulset(deployOptions types.DeployOptions, size resource.Quantity) *appsv1.StatefulSet { - image := "postgres:10.7" + image := "postgres:10.16-alpine" var pullSecrets []corev1.LocalObjectReference if s := kotsadmversion.KotsadmPullSecret(deployOptions.Namespace, deployOptions.KotsadmOptions); s != nil { image = fmt.Sprintf("%s/postgres:%s", kotsadmversion.KotsadmRegistry(deployOptions.KotsadmOptions), kotsadmversion.KotsadmTag(deployOptions.KotsadmOptions)) @@ -33,6 +33,7 @@ func PostgresStatefulset(deployOptions types.DeployOptions, size resource.Quanti } } + passwdFileMode := int32(0644) statefulset := &appsv1.StatefulSet{ TypeMeta: metav1.TypeMeta{ APIVersion: "apps/v1", @@ -85,6 +86,23 @@ func PostgresStatefulset(deployOptions types.DeployOptions, size resource.Quanti }, }, }, + { + Name: "etc-passwd", + VolumeSource: corev1.VolumeSource{ + ConfigMap: &corev1.ConfigMapVolumeSource{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: "kotsadm-postgres", + }, + Items: []corev1.KeyToPath{ + { + Key: "passwd", + Path: "passwd", + Mode: &passwdFileMode, + }, + }, + }, + }, + }, }, Containers: []corev1.Container{ { @@ -102,6 +120,11 @@ func PostgresStatefulset(deployOptions types.DeployOptions, size resource.Quanti Name: "kotsadm-postgres", MountPath: "/var/lib/postgresql/data", }, + { + Name: "etc-passwd", + MountPath: "/etc/passwd", + SubPath: "passwd", + }, }, Env: []corev1.EnvVar{ { diff --git a/pkg/kotsadm/postgres.go b/pkg/kotsadm/postgres.go index eeffa297de..7b99d55c8f 100644 --- a/pkg/kotsadm/postgres.go +++ b/pkg/kotsadm/postgres.go @@ -10,7 +10,6 @@ import ( kotsadmobjects "github.com/replicatedhq/kots/pkg/kotsadm/objects" "github.com/replicatedhq/kots/pkg/kotsadm/types" "github.com/replicatedhq/kots/pkg/logger" - corev1 "k8s.io/api/core/v1" kuberneteserrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -33,6 +32,12 @@ func getPostgresYAML(deployOptions types.DeployOptions) (map[string][]byte, erro return nil, errors.Wrap(err, "failed to get size") } + var configmap bytes.Buffer + if err := s.Encode(kotsadmobjects.PostgresConfigMap(deployOptions), &configmap); err != nil { + return nil, errors.Wrap(err, "failed to marshal postgres statefulset") + } + docs["postgres-configmap.yaml"] = configmap.Bytes() + if err := s.Encode(kotsadmobjects.PostgresStatefulset(deployOptions, size), &statefulset); err != nil { return nil, errors.Wrap(err, "failed to marshal postgres statefulset") } @@ -52,6 +57,10 @@ func ensurePostgres(deployOptions types.DeployOptions, clientset *kubernetes.Cli return errors.Wrap(err, "failed to ensure postgres secret") } + if err := ensurePostgresConfigMap(deployOptions, clientset); err != nil { + return errors.Wrap(err, "failed to ensure postgres configmap") + } + size, err := getSize(deployOptions, "postgres", resource.MustParse("1Gi")) if err != nil { return errors.Wrap(err, "failed to get size") @@ -69,16 +78,33 @@ func ensurePostgres(deployOptions types.DeployOptions, clientset *kubernetes.Cli } func ensurePostgresStatefulset(deployOptions types.DeployOptions, clientset *kubernetes.Clientset, size resource.Quantity) error { - _, err := clientset.AppsV1().StatefulSets(deployOptions.Namespace).Get(context.TODO(), "kotsadm-postgres", metav1.GetOptions{}) + ctx := context.TODO() + desiredPostgres := kotsadmobjects.PostgresStatefulset(deployOptions, size) + existingPostgres, err := clientset.AppsV1().StatefulSets(deployOptions.Namespace).Get(ctx, "kotsadm-postgres", metav1.GetOptions{}) if err != nil { if !kuberneteserrors.IsNotFound(err) { return errors.Wrap(err, "failed to get existing statefulset") } - _, err := clientset.AppsV1().StatefulSets(deployOptions.Namespace).Create(context.TODO(), kotsadmobjects.PostgresStatefulset(deployOptions, size), metav1.CreateOptions{}) + _, err := clientset.AppsV1().StatefulSets(deployOptions.Namespace).Create(ctx, desiredPostgres, metav1.CreateOptions{}) if err != nil { return errors.Wrap(err, "failed to create postgres statefulset") } + + return nil + } + + if len(existingPostgres.Spec.Template.Spec.Containers) != 1 || len(desiredPostgres.Spec.Template.Spec.Containers) != 1 { + return errors.New("postgres stateful set cannot be upgraded") + } + + existingPostgres.Spec.Template.Spec.Volumes = desiredPostgres.Spec.Template.Spec.DeepCopy().Volumes + existingPostgres.Spec.Template.Spec.Containers[0].Image = desiredPostgres.Spec.Template.Spec.Containers[0].Image + existingPostgres.Spec.Template.Spec.Containers[0].VolumeMounts = desiredPostgres.Spec.Template.Spec.Containers[0].DeepCopy().VolumeMounts + + _, err = clientset.AppsV1().StatefulSets(deployOptions.Namespace).Update(ctx, existingPostgres, metav1.UpdateOptions{}) + if err != nil { + return errors.Wrap(err, "failed to update postgres statefulset") } return nil @@ -108,15 +134,13 @@ func waitForHealthyPostgres(deployOptions types.DeployOptions, clientset *kubern start := time.Now() for { - pods, err := clientset.CoreV1().Pods(deployOptions.Namespace).List(context.TODO(), metav1.ListOptions{LabelSelector: "app=kotsadm-postgres"}) + s, err := clientset.AppsV1().StatefulSets(deployOptions.Namespace).Get(context.TODO(), "kotsadm-postgres", metav1.GetOptions{}) if err != nil { return errors.Wrap(err, "failed to list pods") } - for _, pod := range pods.Items { - if pod.Status.Phase == corev1.PodRunning { - return nil - } + if s.Status.ReadyReplicas == *s.Spec.Replicas && s.Status.UpdateRevision == s.Status.CurrentRevision { + return nil } time.Sleep(time.Second) diff --git a/pkg/kotsadm/secrets.go b/pkg/kotsadm/secrets.go index 7198194cb0..8ecf939e07 100644 --- a/pkg/kotsadm/secrets.go +++ b/pkg/kotsadm/secrets.go @@ -110,7 +110,7 @@ func ensureSecrets(deployOptions *types.DeployOptions, clientset *kubernetes.Cli User: "dex", } if err := identitydeploy.EnsurePostgresSecret(context.TODO(), clientset, deployOptions.Namespace, "kotsadm", nil, postgresConfig, nil); err != nil { - return errors.Wrap(err, "failed to ensure postgres secret") + return errors.Wrap(err, "failed to ensure postgres secret for identity") } if deployOptions.SharedPasswordBcrypt == "" {