Merge branch 'master' into default-db-roles

This commit is contained in:
Felix Kunde 2019-10-29 12:05:17 +01:00
commit e2bf0fdedf
14 changed files with 76 additions and 21 deletions

View File

@ -87,6 +87,12 @@ rules:
- list - list
- watch - watch
- patch - patch
- apiGroups:
- ""
resources:
- pods/exec
verbs:
- create
- apiGroups: - apiGroups:
- "" - ""
resources: resources:

View File

@ -66,7 +66,7 @@ configKubernetes:
# list of labels that can be inherited from the cluster manifest # list of labels that can be inherited from the cluster manifest
# inherited_labels: # inherited_labels:
# - application # - application
# - app # - environment
# timeout for successful migration of master pods from unschedulable node # timeout for successful migration of master pods from unschedulable node
# master_pod_move_timeout: 20m # master_pod_move_timeout: 20m

View File

@ -62,7 +62,7 @@ configKubernetes:
# infrastructure_roles_secret_name: postgresql-infrastructure-roles # infrastructure_roles_secret_name: postgresql-infrastructure-roles
# list of labels that can be inherited from the cluster manifest # list of labels that can be inherited from the cluster manifest
# inherited_labels: "" # inherited_labels: application,environment
# timeout for successful migration of master pods from unschedulable node # timeout for successful migration of master pods from unschedulable node
# master_pod_move_timeout: 20m # master_pod_move_timeout: 20m

View File

@ -14,8 +14,9 @@ PG_BIN=$PG_DIR/$PG_VERSION/bin
DUMP_SIZE_COEFF=5 DUMP_SIZE_COEFF=5
TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token) TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
K8S_API_URL=https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_SERVICE_PORT/api/v1 K8S_API_URL=https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_SERVICE_PORT
CERT=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt CERT=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt
CLUSTER_NAME_LABEL=cluster-name
function estimate_size { function estimate_size {
"$PG_BIN"/psql -tqAc "${ALL_DB_SIZE_QUERY}" "$PG_BIN"/psql -tqAc "${ALL_DB_SIZE_QUERY}"
@ -48,33 +49,63 @@ function aws_upload {
function get_pods { function get_pods {
declare -r SELECTOR="$1" declare -r SELECTOR="$1"
curl "${K8S_API_URL}/namespaces/${POD_NAMESPACE}/pods?$SELECTOR" \ curl "${K8S_API_URL}/api/v1/namespaces/${POD_NAMESPACE}/pods?$SELECTOR" \
--cacert $CERT \ --cacert $CERT \
-H "Authorization: Bearer ${TOKEN}" | jq .items[].status.podIP -r -H "Authorization: Bearer ${TOKEN}" | jq .items[].status.podIP -r
} }
function get_current_pod { function get_current_pod {
curl "${K8S_API_URL}/namespaces/${POD_NAMESPACE}/pods?fieldSelector=metadata.name%3D${HOSTNAME}" \ curl "${K8S_API_URL}/api/v1/namespaces/${POD_NAMESPACE}/pods?fieldSelector=metadata.name%3D${HOSTNAME}" \
--cacert $CERT \ --cacert $CERT \
-H "Authorization: Bearer ${TOKEN}" -H "Authorization: Bearer ${TOKEN}"
} }
declare -a search_strategy=( declare -a search_strategy=(
get_cluster_name_label
list_all_replica_pods_current_node list_all_replica_pods_current_node
list_all_replica_pods_any_node list_all_replica_pods_any_node
get_master_pod get_master_pod
) )
function get_config_resource() {
curl "${K8S_API_URL}/apis/apps/v1/namespaces/default/deployments/postgres-operator" \
--cacert $CERT \
-H "Authorization: Bearer ${TOKEN}" | jq '.spec.template.spec.containers[0].env[] | select(.name == "$1") | .value'
}
function get_cluster_name_label {
local config
local clustername
config=$(get_config_resource "CONFIG_MAP_NAME")
if [ -n "$config" ]; then
clustername=$(curl "${K8S_API_URL}/api/v1/namespaces/default/configmaps/${config}" \
--cacert $CERT \
-H "Authorization: Bearer ${TOKEN}" | jq '.data.cluster_name_label')
else
config=$(get_config_resource "POSTGRES_OPERATOR_CONFIGURATION_OBJECT")
if [ -n "$config" ]; then
clustername=$(curl "${K8S_API_URL}/apis/acid.zalan.do/v1/namespaces/default/operatorconfigurations/${config}" \
--cacert $CERT \
-H "Authorization: Bearer ${TOKEN}" | jq '.configuration.kubernetes.cluster_name_label')
fi
fi
if [ -n "$clustername" ]; then
CLUSTER_NAME_LABEL=${clustername}
fi;
}
function list_all_replica_pods_current_node { function list_all_replica_pods_current_node {
get_pods "labelSelector=version%3D${SCOPE},spilo-role%3Dreplica&fieldSelector=spec.nodeName%3D${CURRENT_NODENAME}" | head -n 1 get_pods "labelSelector=${CLUSTER_NAME_LABEL}%3D${SCOPE},spilo-role%3Dreplica&fieldSelector=spec.nodeName%3D${CURRENT_NODENAME}" | head -n 1
} }
function list_all_replica_pods_any_node { function list_all_replica_pods_any_node {
get_pods "labelSelector=version%3D${SCOPE},spilo-role%3Dreplica" | head -n 1 get_pods "labelSelector=${CLUSTER_NAME_LABEL}%3D${SCOPE},spilo-role%3Dreplica" | head -n 1
} }
function get_master_pod { function get_master_pod {
get_pods "labelSelector=version%3D${SCOPE},spilo-role%3Dmaster" | head -n 1 get_pods "labelSelector=${CLUSTER_NAME_LABEL}%3D${SCOPE},spilo-role%3Dmaster" | head -n 1
} }
CURRENT_NODENAME=$(get_current_pod | jq .items[].spec.nodeName --raw-output) CURRENT_NODENAME=$(get_current_pod | jq .items[].spec.nodeName --raw-output)

View File

@ -184,6 +184,7 @@ parameter of the PDB is set to `1` which prevents killing masters in single-node
clusters and/or the last remaining running instance in a multi-node cluster. clusters and/or the last remaining running instance in a multi-node cluster.
The PDB is only relaxed in two scenarios: The PDB is only relaxed in two scenarios:
* If a cluster is scaled down to `0` instances (e.g. for draining nodes) * If a cluster is scaled down to `0` instances (e.g. for draining nodes)
* If the PDB is disabled in the configuration (`enable_pod_disruption_budget`) * If the PDB is disabled in the configuration (`enable_pod_disruption_budget`)
@ -200,6 +201,18 @@ Postgres cluster, in order to identify its child objects. The typical use case
is to add labels that identifies the `Pods` created by the operator, in order is to add labels that identifies the `Pods` created by the operator, in order
to implement fine-controlled `NetworkPolicies`. to implement fine-controlled `NetworkPolicies`.
**postgres-operator ConfigMap**
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: postgres-operator
data:
inherited_labels: application,environment
...
```
**OperatorConfiguration** **OperatorConfiguration**
```yaml ```yaml

View File

@ -80,7 +80,7 @@ is prepended to the operator resource's names.
Use `--name zalando` to match with the default service account name as older Use `--name zalando` to match with the default service account name as older
operator versions do not support custom names for service accounts. To use operator versions do not support custom names for service accounts. To use
CRD-based configuration you need to specify the [values-crd yaml file](../charts/values-crd.yaml). CRD-based configuration you need to specify the [values-crd yaml file](../charts/postgres-operator/values-crd.yaml).
```bash ```bash
# 1) initialize helm # 1) initialize helm

View File

@ -2,6 +2,8 @@ apiVersion: "acid.zalan.do/v1"
kind: postgresql kind: postgresql
metadata: metadata:
name: acid-test-cluster name: acid-test-cluster
# labels:
# environment: demo
spec: spec:
dockerImage: registry.opensource.zalan.do/acid/spilo-11:1.6-p1 dockerImage: registry.opensource.zalan.do/acid/spilo-11:1.6-p1
initContainers: initContainers:

View File

@ -31,7 +31,7 @@ data:
enable_teams_api: "false" enable_teams_api: "false"
# etcd_host: "" # etcd_host: ""
# infrastructure_roles_secret_name: postgresql-infrastructure-roles # infrastructure_roles_secret_name: postgresql-infrastructure-roles
# inherited_labels: "" # inherited_labels: application,environment
# kube_iam_role: "" # kube_iam_role: ""
# log_s3_bucket: "" # log_s3_bucket: ""
# logical_backup_docker_image: "registry.opensource.zalan.do/acid/logical-backup" # logical_backup_docker_image: "registry.opensource.zalan.do/acid/logical-backup"

View File

@ -88,6 +88,12 @@ rules:
- list - list
- watch - watch
- patch - patch
- apiGroups:
- ""
resources:
- pods/exec
verbs:
- create
- apiGroups: - apiGroups:
- "" - ""
resources: resources:

View File

@ -27,7 +27,7 @@ configuration:
# infrastructure_roles_secret_name: "" # infrastructure_roles_secret_name: ""
# inherited_labels: # inherited_labels:
# - application # - application
# - app # - environment
# node_readiness_label: "" # node_readiness_label: ""
oauth_token_secret_name: postgresql-operator oauth_token_secret_name: postgresql-operator
pdb_name_format: "postgres-{cluster}-pdb" pdb_name_format: "postgres-{cluster}-pdb"

View File

@ -329,7 +329,7 @@ func (c *Cluster) deleteStatefulSet() error {
return fmt.Errorf("could not delete pods: %v", err) return fmt.Errorf("could not delete pods: %v", err)
} }
if err := c.deletePersistenVolumeClaims(); err != nil { if err := c.deletePersistentVolumeClaims(); err != nil {
return fmt.Errorf("could not delete PersistentVolumeClaims: %v", err) return fmt.Errorf("could not delete PersistentVolumeClaims: %v", err)
} }

View File

@ -30,7 +30,7 @@ func (c *Cluster) listPersistentVolumeClaims() ([]v1.PersistentVolumeClaim, erro
return pvcs.Items, nil return pvcs.Items, nil
} }
func (c *Cluster) deletePersistenVolumeClaims() error { func (c *Cluster) deletePersistentVolumeClaims() error {
c.logger.Debugln("deleting PVCs") c.logger.Debugln("deleting PVCs")
pvcs, err := c.listPersistentVolumeClaims() pvcs, err := c.listPersistentVolumeClaims()
if err != nil { if err != nil {

View File

@ -58,7 +58,6 @@ type Controller struct {
PodServiceAccount *v1.ServiceAccount PodServiceAccount *v1.ServiceAccount
PodServiceAccountRoleBinding *rbacv1beta1.RoleBinding PodServiceAccountRoleBinding *rbacv1beta1.RoleBinding
namespacesWithDefinedRBAC sync.Map
} }
// NewController creates a new controller // NewController creates a new controller

View File

@ -493,17 +493,16 @@ func (c *Controller) postgresqlDelete(obj interface{}) {
} }
/* /*
Ensures the pod service account and role bindings exists in a namespace before a PG cluster is created there so that a user does not have to deploy these credentials manually. Ensures the pod service account and role bindings exists in a namespace
StatefulSets require the service account to create pods; Patroni requires relevant RBAC bindings to access endpoints. before a PG cluster is created there so that a user does not have to deploy
these credentials manually. StatefulSets require the service account to
create pods; Patroni requires relevant RBAC bindings to access endpoints.
The operator does not sync accounts/role bindings after creation. The operator does not sync accounts/role bindings after creation.
*/ */
func (c *Controller) submitRBACCredentials(event ClusterEvent) error { func (c *Controller) submitRBACCredentials(event ClusterEvent) error {
namespace := event.NewSpec.GetNamespace() namespace := event.NewSpec.GetNamespace()
if _, ok := c.namespacesWithDefinedRBAC.Load(namespace); ok {
return nil
}
if err := c.createPodServiceAccount(namespace); err != nil { if err := c.createPodServiceAccount(namespace); err != nil {
return fmt.Errorf("could not create pod service account %v : %v", c.opConfig.PodServiceAccountName, err) return fmt.Errorf("could not create pod service account %v : %v", c.opConfig.PodServiceAccountName, err)
@ -512,7 +511,6 @@ func (c *Controller) submitRBACCredentials(event ClusterEvent) error {
if err := c.createRoleBindings(namespace); err != nil { if err := c.createRoleBindings(namespace); err != nil {
return fmt.Errorf("could not create role binding %v : %v", c.PodServiceAccountRoleBinding.Name, err) return fmt.Errorf("could not create role binding %v : %v", c.PodServiceAccountRoleBinding.Name, err)
} }
c.namespacesWithDefinedRBAC.Store(namespace, true)
return nil return nil
} }