Container

Containerization, Docker, Kubernetes

Installing Helm, nginx-ingress, and cert-manager

Installing Helm

This instruction is based on Helm v3.1.2

You should use Helm v3.3.1 or newer if you want to install CRD together in cert-manager v0.16 or newer. See

Visit Helm Installation Guide to install Helm on your local.

Verify the current version.

helm version
version.BuildInfo{Version:"v3.1.2", GitCommit:"d878d4d45863e42fd5cff6743294a11d28a9abce", GitTreeState:"clean", GoVersion:"go1.13.8"}

Add the official Helm stable repository.

helm repo add stable https://kubernetes-charts.storage.googleapis.com/

The stable repository URL has been changed to https://charts.helm.sh/stable 

"stable" has been added to your repositories

Verify repository.

helm repo list
NAME    URL
stable  https://kubernetes-charts.storage.googleapis.com/

Update repo to get the latest list of charts

helm repo update
Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the "stable" chart repository
Update Complete. ⎈ Happy Helming!⎈

Installing nginx-ingress

Install nginx-ingress.

helm install stable/nginx-ingress --namespace kube-system --set controller.replicaCount=2 --generate-name
NAME: nginx-ingress-1576935072
LAST DEPLOYED: Sat Dec 21 20:31:17 2019
NAMESPACE: kube-system
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
The nginx-ingress controller has been installed.
It may take a few minutes for the LoadBalancer IP to be available.
You can watch the status by running 'kubectl --namespace kube-system get services -o wide -w nginx-ingress-1576935072-controller'

An example Ingress that makes use of the controller:

  apiVersion: extensions/v1beta1
  kind: Ingress
  metadata:
    annotations:
      kubernetes.io/ingress.class: nginx
    name: example
    namespace: foo
  spec:
    rules:
      - host: www.example.com
        http:
          paths:
            - backend:
                serviceName: exampleService
                servicePort: 80
              path: /
    # This section is only required if TLS is to be enabled for the Ingress
    tls:
        - hosts:
            - www.example.com
          secretName: example-tls

If TLS is enabled for the Ingress, a Secret containing the certificate and key must also be provided:

  apiVersion: v1
  kind: Secret
  metadata:
    name: example-tls
    namespace: foo
  data:
    tls.crt: <base64 encoded cert>
    tls.key: <base64 encoded key>
  type: kubernetes.io/tls

Get the LoadBalancer public IP address by waiting until EXTERNAL-IP changed from <Pending>.

kubectl get service -l app=nginx-ingress --namespace kube-system
NAME                                       TYPE           CLUSTER-IP     EXTERNAL-IP     PORT(S)                      AGE
nginx-ingress-1576935072-controller        LoadBalancer   10.0.211.130   20.43.176.132   80:31434/TCP,443:30957/TCP   2m43s
nginx-ingress-1576935072-default-backend   ClusterIP      10.0.41.247    <none>          80/TCP                       2m43s

Installing cert-manager

This instruction is based on cert-manager v.0.14 which support Kubernetes v1.15+.
See cert-manager on Kubernetes Installation Guide for more information

In v0.16 or newer, you can install cert-manager along with CRDs in one shot using command:
helm install cert-manager jetstack/cert-manager --set installCRDs=true --namespace cert-manager

Installing custom resource definitions (CRD).

kubectl apply --validate=false -f https://github.com/jetstack/cert-manager/releases/download/v0.14.0/cert-manager.crds.yaml
customresourcedefinition.apiextensions.k8s.io/certificaterequests.cert-manager.io created
customresourcedefinition.apiextensions.k8s.io/certificates.cert-manager.io created
customresourcedefinition.apiextensions.k8s.io/challenges.acme.cert-manager.io created
customresourcedefinition.apiextensions.k8s.io/clusterissuers.cert-manager.io created
customresourcedefinition.apiextensions.k8s.io/issuers.cert-manager.io created
customresourcedefinition.apiextensions.k8s.io/orders.acme.cert-manager.io created

Create namespace.

kubectl create namespace cert-manager
namespace/cert-manager created

Add the Jetstack's Helm repository.

helm repo add jetstack https://charts.jetstack.io
"jetstack" has been added to your repositories

Update local charts from the repositories.

helm repo update
Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the "jetstack" chart repository
...Successfully got an update from the "stable" chart repository
Update Complete. ⎈ Happy Helming!⎈

Install cert-manager.

helm install cert-manager jetstack/cert-manager --namespace cert-manager --version v0.14.0
NAME: cert-manager
LAST DEPLOYED: Sat Mar 28 10:40:54 2020
NAMESPACE: cert-manager
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
cert-manager has been deployed successfully!

In order to begin issuing certificates, you will need to set up a ClusterIssuer
or Issuer resource (for example, by creating a 'letsencrypt-staging' issuer).

More information on the different types of issuers and how to configure them
can be found in our documentation:

https://docs.cert-manager.io/en/latest/reference/issuers.html

For information on how to configure cert-manager to automatically provision
Certificates for Ingress resources, take a look at the `ingress-shim`
documentation:

https://docs.cert-manager.io/en/latest/reference/ingress-shim.html

Verify all pods are up and running.

kubectl get pod --namespace=cert-manager
NAME                                       READY     STATUS    RESTARTS   AGE
cert-manager-5d8d74bb4d-g4jzs              1/1       Running   0          36s
cert-manager-cainjector-5db54b6b45-bnjpv   1/1       Running   0          36s
cert-manager-webhook-7cd5d4fdd7-59mwk      1/1       Running   0          36s

Configuring ACME as ClusterIssuer

See cert-manager ACME Configuration Guide for more information.

Create file cluster-issuer.yaml  with below content for configuring ACME as the ClusterIssuer with HTTP01 challenge solver configuration.

Don't forget to update email with your email address.

apiVersion: cert-manager.io/v1alpha2
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: your.email@domain.com
    privateKeySecretRef:
      name: letsencrypt-prod
    solvers:
    - http01:
        ingress:
          class: nginx

Apply the configuration.

$ kubectl apply -f cluster-issuer.yaml
clusterissuer.cert-manager.io/letsencrypt-prod created

Verify ClusterIssuer is ready (READY must be True).

kubectl get clusterissuer,issuer,certificates --all-namespaces
NAME                                             READY   AGE
clusterissuer.cert-manager.io/letsencrypt-prod   True    20s

Listing All Installed Releases

helm list --all-namespaces
NAME                            NAMESPACE       REVISION        UPDATED                                 STATUS         CHART                  APP VERSION
cert-manager                    cert-manager    1               2020-03-28 10:40:54.2689133 +0700 +07   deployed       cert-manager-v0.14.0   v0.14.0
nginx-ingress-1585365422        kube-system     1               2020-03-28 10:17:06.6095955 +0700 +07   deployed       nginx-ingress-1.34.2   0.30.0

 

How to Setup MediaWiki with Docker

Install

1) Install Mediawiki with sudo docker container run -d --name mediawiki -p 8080:80 mediawiki

2) Install MySQL with sudo docker container run -d --name mediawiki-mysql -v mediawiki-mysql:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=<root_pwd> mysql

You can additionally install SMTP server with sudo docker run -d --name mediawiki-smtp namshi/smtp

3) Create a new network with sudo docker network create mediawiki

4) Put all containers into a new network.

$ sudo docker network connect mediawiki mediawiki
$ sudo docker network connect mediawiki mediawiki-mysql
$ sudo docker network connect mediawiki mediawiki-smtp

Configure

1) Access your wiki at http://<host>:8080

2) Click to set up wiki

Mediawiki First Page

3) Select language and click Continue

Wiki Language

4) Leave default and click Continue

Wiki Env Check

5) Input your MySQL container name and its root password

Wiki Db Setup

6) Leave default and click Continue

Wiki Db Settings

7) Assign your wiki name and create your wiki account

Wiki Name Account

8) Click Continue to start configure

Wiki Install

9) Once done, click Continue again to download LocalSettings.php file.

Wiki Install Completed

10) Transfer this file into the container

sudo docker cp LocalSettings.php mediawiki:/var/www/html

11) You wiki is ready to use at http://<host>:8080/index.php/Main_Page

Wiki Main Page

Email Function

(WIP, Not Workable Solution yet)

Mailer returned: Failed to add recipient: pacroy@gmail.com [SMTP: Invalid response code received from server (code: 550, response: relay not permitted)] 

To get email function work within Wiki, please proceed the following:

1) Edit LocalSettings.php and add the following lines

$wgSMTP = array(
	'host'     => "mediawiki-smtp", // could also be an IP address. Where the SMTP server is located
	'IDHost'   => "chairat.me",     // Generally this will be the domain name of your website (aka mywiki.org)
	'port'     => 25,               // Port to use when connecting to the SMTP server
	'auth'     => false             // Should we use SMTP authentication (true or false)
   );

Reference: https://www.mediawiki.org/wiki/Manual:$wgSMTP

2) Copy into container sudo docker cp LocalSettings.php mediawiki:/var/www/html

How to Deploy BookStack Wiki App

https://www.bookstackapp.com/

Docker Commands

docker network create bookstack_nw

docker run -d --net bookstack_nw  \
-e MYSQL_ROOT_PASSWORD=secret \
-e MYSQL_DATABASE=bookstack \
-e MYSQL_USER=bookstack \
-e MYSQL_PASSWORD=secret \
-v bookstack-mysql:/var/lib/mysql \
 --name="bookstack_db" \
 mysql:5.7.21

docker run -d --net bookstack_nw  \
-e DB_HOST=bookstack_db:3306 \
-e DB_DATABASE=bookstack \
-e DB_USERNAME=bookstack \
-e DB_PASSWORD=secret \
-e AZURE_APP_ID=*** \
-e AZURE_APP_SECRET=*** \
-e AZURE_TENANT=*** \
-e APP_URL=https://www.domain.com \
-v bookstack-uploads:/var/www/bookstack/public/uploads \
-v bookstack-storage:/var/www/bookstack/public/storage \
-p 8080:80 \
 --name="bookstack" \
 solidnerd/bookstack:0.24.2

docker run -d --net bookstack_nw \
-v ~/nginx:/etc/nginx/conf.d/ \
-p 80:80 -p 443:443 \
--name=nginx \
nginx

nginx config

server {
    listen 80;
    listen [::]:80;
    server_name _;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl;
    listen [::]:443;

    server_name  www.domain.com;

    ssl_session_timeout 1d;
    ssl_session_cache shared:SSL:50m;
    ssl_session_tickets off;

    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 E                                                                                                                                                                                            ECDH EDH+aRSA !RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS";
    ssl_prefer_server_ciphers on;

    ssl_certificate     /etc/nginx/conf.d/fullchain.pem;
    ssl_certificate_key /etc/nginx/conf.d/privkey.pem;
    #charset koi8-r;
    #access_log  /var/log/nginx/host.access.log  main;

    location / {
        proxy_pass http://bookstack:80;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_read_timeout 43200000;

        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_set_header X-NginX-Proxy true;
    }

}

SSL Certificates

Self-signed
openssl req -x509 -newkey rsa:2048 \
-keyout key.pem -out cert.pem \
-days 30000 -nodes
Let's encrypt

https://letsencrypt.org/getting-started/

mysql Deployment Config

apiVersion: apps.openshift.io/v1
kind: DeploymentConfig
metadata:
  labels:
    app: cakephp-mysql-persistent
    template: cakephp-mysql-persistent
  name: mysql
spec:
  replicas: 1
  selector:
    name: mysql
  strategy:
    activeDeadlineSeconds: 21600
    recreateParams:
      timeoutSeconds: 600
    resources: {}
    type: Recreate
  template:
    metadata:
      creationTimestamp: null
      labels:
        name: mysql
      name: mysql
    spec:
      containers:
        - env:
            - name: MYSQL_USER
              valueFrom:
                secretKeyRef:
                  key: database-user
                  name: cakephp-mysql-persistent
            - name: MYSQL_PASSWORD
              valueFrom:
                secretKeyRef:
                  key: database-password
                  name: cakephp-mysql-persistent
            - name: MYSQL_DATABASE
              value: default
          image: >-
            server:5000/rhscl/mysql-57-rhel7@sha256:154cd19e9c2a9df09ad61ce61139b955499aecd2247eb32df299104c750c6feb
          imagePullPolicy: IfNotPresent
          livenessProbe:
            failureThreshold: 3
            initialDelaySeconds: 30
            periodSeconds: 10
            successThreshold: 1
            tcpSocket:
              port: 3306
            timeoutSeconds: 1
          name: mysql
          ports:
            - containerPort: 3306
              protocol: TCP
          readinessProbe:
            exec:
              command:
                - /bin/sh
                - '-i'
                - '-c'
                - >-
                  MYSQL_PWD='ymVAEh4ufpMShxgn' mysql -h 127.0.0.1 -u cakephp -D
                  default -e 'SELECT 1'
            failureThreshold: 3
            initialDelaySeconds: 5
            periodSeconds: 10
            successThreshold: 1
            timeoutSeconds: 1
          resources:
            limits:
              memory: 512Mi
          terminationMessagePath: /dev/termination-log
          terminationMessagePolicy: File
          volumeMounts:
            - mountPath: /var/lib/mysql/data
              name: mysql-data
      dnsPolicy: ClusterFirst
      restartPolicy: Always
      schedulerName: default-scheduler
      securityContext: {}
      terminationGracePeriodSeconds: 30
      volumes:
        - name: mysql-data
          persistentVolumeClaim:
            claimName: mysql
  test: false
  triggers:
    - imageChangeParams:
        automatic: true
        containerNames:
          - mysql
        from:
          kind: ImageStreamTag
          name: 'mysql:5.7'
          namespace: openshift
        lastTriggeredImage: >-
          hoecprvnex01.na.xom.com:5000/rhscl/mysql-57-rhel7@sha256:154cd19e9c2a9df09ad61ce61139b955499aecd2247eb32df299104c750c6feb
      type: ImageChange
    - type: ConfigChange

References

Useful MySQL Commands

Users

List All Users

mysql> select * from mysql.user;
mysql> select host, user, authentication_string from mysql.user;

References

Create Users

mysql> CREATE USER 'newuser'@'localhost' IDENTIFIED BY 'password';
mysql> GRANT ALL PRIVILEGES ON database . * TO 'newuser'@'localhost';
mysql> FLUSH PRIVILEGES;

References

Databases

List Databases

mysql> show databases;

Change Database

mysql> use db_name;

Show Tables in Database

mysql> show tables;

References

Backup and Restore

Backup

$ mysqldump -p --all-databases > bookstack.sql

References

Restore

$ mysql < bookstack.sql
$ mysql < 'FLUSH PRIVILEGES;'

References

Running Git Server using Gogs on Docker

Create network

docker network create gogs

Create MySQL

docker run -d --net gogs  \
-e MYSQL_ROOT_PASSWORD=secret \
-e MYSQL_DATABASE=gogs \
-e MYSQL_USER=gogs \
-e MYSQL_PASSWORD=secret \
 --name="gogs_db" \
 -v gogs_mysql:/var/lib/mysql \
 mysql:5.7

Create Gogs

docker run -d --net gogs \
--name=gogs \
-p 10022:22 \
-p 10080:3000 \
-v gogs_data:/data \
gogs/gogs

Remote shell into MySQL container.

docker exec -it gogs_db bash

Execute these commands in MySQL container.

SET GLOBAL innodb_file_per_table = ON,
           innodb_file_format = Barracuda,
           innodb_large_prefix = ON;
DROP DATABASE IF EXISTS gogs;
CREATE DATABASE IF NOT EXISTS gogs CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;

Go to http://localhost:10080/install and configure Gogs.