<#import "/templates/guide.adoc" as tmpl>
<#import "/templates/kc.adoc" as kc>
<#import "/templates/options.adoc" as opts>
<#import "/templates/links.adoc" as links>
<#import "/templates/profile.adoc" as profile>

<@tmpl.guide
title="Basic {project_name} deployment"
priority=20
summary="How to install {project_name} using the Operator">

== Performing a basic {project_name} deployment
This {section} describes how to perform a basic {project_name} Deployment on
<@profile.ifCommunity>
Kubernetes or
</@profile.ifCommunity>
OpenShift using the Operator.

=== Preparing for deployment

Once the {project_name} Operator is installed and running in the cluster namespace, you can set up the other deployment prerequisites.

* Database
* Hostname
* TLS Certificate and associated keys

==== Database

A database should be available and accessible from the cluster namespace where {project_name} is installed.
For a list of supported databases, see <@links.server id="db"/>.
The {project_name} Operator does not manage the database and you need to provision it yourself. Consider verifying your cloud provider offering or using a database operator.

For development purposes, you can use an ephemeral PostgreSQL pod installation. To provision it, follow the approach below:

Create YAML file `example-postgres.yaml`:
[source,yaml]
----
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: postgresql-db
spec:
  serviceName: postgresql-db-service
  selector:
    matchLabels:
      app: postgresql-db
  replicas: 1
  template:
    metadata:
      labels:
        app: postgresql-db
    spec:
      containers:
        - name: postgresql-db
          image: postgres:latest
          volumeMounts:
            - mountPath: /data
              name: cache-volume
          env:
            - name: POSTGRES_PASSWORD
              value: testpassword
            - name: PGDATA
              value: /data/pgdata
            - name: POSTGRES_DB
              value: keycloak
      volumes:
        - name: cache-volume
          emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
  name: postgres-db
spec:
  selector:
    app: postgresql-db
  type: LoadBalancer
  ports:
  - port: 5432
    targetPort: 5432
----

Apply the changes:

[source,bash]
----
kubectl apply -f example-postgres.yaml
----

==== Hostname

For a production ready installation, you need a hostname that can be used to contact {project_name}.
See <@links.server id="hostname"/> for the available configurations.

For development purposes, this {section} will use `test.keycloak.org`.

When running on OpenShift, with ingress enabled, and with the spec.ingress.classname set to openshift-default, you may leave the spec.hostname.hostname unpopulated in the Keycloak CR.
The operator will assign a default hostname to the stored version of the CR similar to what would be created by an OpenShift Route without an explicit host - that is ingress-namespace.appsDomain
If the appsDomain changes, or should you need a different hostname for any reason, then update the Keycloak CR.

==== TLS Certificate and key

See your Certification Authority to obtain the certificate and the key.

For development purposes, you can enter this command to obtain a self-signed certificate:

[source,bash]
----
openssl req -subj '/CN=test.keycloak.org/O=Test Keycloak./C=US' -newkey rsa:2048 -nodes -keyout key.pem -x509 -days 365 -out certificate.pem
----

You should install it in the cluster namespace as a Secret by entering this command:

[source,bash]
----
kubectl create secret tls example-tls-secret --cert certificate.pem --key key.pem
----

=== Deploying {project_name}

To deploy {project_name}, you create a Custom Resource (CR) based on the Keycloak Custom Resource Definition (CRD).

Consider storing the Database credentials in a separate Secret. Enter the following commands:
[source,bash]
----
kubectl create secret generic keycloak-db-secret \
  --from-literal=username=[your_database_username] \
  --from-literal=password=[your_database_password]
----

You can customize several fields using the Keycloak CRD. For a basic deployment, you can stick to the following approach:

Create YAML file `example-kc.yaml`:
[source,yaml]
----
apiVersion: k8s.keycloak.org/v2alpha1
kind: Keycloak
metadata:
  name: example-kc
spec:
  instances: 1
  db:
    vendor: postgres
    host: postgres-db
    usernameSecret:
      name: keycloak-db-secret
      key: username
    passwordSecret:
      name: keycloak-db-secret
      key: password
  http:
    tlsSecret: example-tls-secret
  hostname:
    hostname: test.keycloak.org
----

Apply the changes:

[source,bash]
----
kubectl apply -f example-kc.yaml
----

To check that the {project_name} instance has been provisioned in the cluster, check the status of the created CR by entering the following command:

[source,bash]
----
kubectl get keycloaks/example-kc -o go-template='{{range .status.conditions}}CONDITION: {{.type}}{{"\n"}}  STATUS: {{.status}}{{"\n"}}  MESSAGE: {{.message}}{{"\n"}}{{end}}'
----

When the deployment is ready, look for output similar to the following:

[source,bash]
----
CONDITION: Ready
  STATUS: true
  MESSAGE:
CONDITION: HasErrors
  STATUS: false
  MESSAGE:
CONDITION: RollingUpdate
  STATUS: false
  MESSAGE:
----

=== Accessing the {project_name} deployment

The {project_name} deployment is exposed through a basic Ingress and is accessible through the provided hostname.  On installations with multiple default IngressClass instances
or when running on OpenShift 4.12+ you should provide an ingressClassName by setting `ingress` spec with `className` property to the desired class name:

Edit YAML file `example-kc.yaml`:

[source,yaml]
----
apiVersion: k8s.keycloak.org/v2alpha1
kind: Keycloak
metadata:
  name: example-kc
spec:
    ...
    ingress:
      className: openshift-default
----

If the default ingress does not fit your use case, disable it by setting `ingress` spec with `enabled` property to `false` value:

Edit YAML file `example-kc.yaml`:

[source,yaml]
----
apiVersion: k8s.keycloak.org/v2alpha1
kind: Keycloak
metadata:
  name: example-kc
spec:
    ...
    ingress:
      enabled: false
----

Apply the changes:

[source,bash]
----
kubectl apply -f example-kc.yaml
----
You can provide an alternative ingress resource pointing to the service `<keycloak-cr-name>-service`.

For debugging and development purposes, consider directly connecting to the {project_name} service using a port forward. For example, enter this command:

[source,bash]
----
kubectl port-forward service/example-kc-service 8443:8443
----

=== Accessing the Admin Console

When deploying {project_name}, the operator generates an arbitrary initial admin `username` and `password` and stores those credentials as a basic-auth Secret object in the same namespace as the CR.

[WARNING]
====
Change the default admin credentials and enable MFA in {project_name} before going to production.
====

To fetch the initial admin credentials, you have to read and decode the Secret.
The Secret name is derived from the Keycloak CR name plus the fixed suffix `-initial-admin`.
To get the username and password for the `example-kc` CR, enter the following commands:

[source,bash]
----
kubectl get secret example-kc-initial-admin -o jsonpath='{.data.username}' | base64 --decode
kubectl get secret example-kc-initial-admin -o jsonpath='{.data.password}' | base64 --decode
----

You can use those credentials to access the Admin Console or the Admin REST API.

</@tmpl.guide>
