Kubernetes: Cannot deploy flask web app with apache and https

6/26/2016

I have a local Kubernetes cluster on a single machine, and I successfully deployed a flask web app using apache server, so there shouldn't be any problem with the cluster setup. However, I need to upgrade the website to https, so I used letsencrypt to generate ssl certificates and volume mapped them into the container. I also successfully deployed the app without docker, i.e. directly start the apache server using sudo /usr/sbin/apache2ctl -D FOREGROUND. I can visit my website at https://XXX.XXX.XXX.edu without problem.

However, when I started putting everything into Docker and Kubernetes, and visited https://XXX.XXX.XXX.edu:30001, the browser gave me this error:

This site can’t be reached

XXX.XXX.XXX.edu took too long to respond

Here is how I deployed:

I first started the service kubectl create -f web-service.yaml:

apiVersion: v1
kind: Service
metadata:
  name: web
  labels:
    name: web
    role: "ssl-proxy"
spec:
  type: NodePort
  ports:
    - nodePort: 30001
      name: "https"
      port: 443
      targetPort: 443
      protocol: "TCP"
    - nodePort: 30000
      name: "http"
      port: 80
      targetPort: 80
      protocol: "TCP"
  selector:
    name: web
    role: "ssl-proxy"

Then I started the pod kubectl create -f web-controller.yaml:

apiVersion: v1
kind: ReplicationController
metadata:
  labels:
    name: web
  name: web-controller
spec:
  replicas: 1
  selector:
    name: web
  template:
    metadata:
      labels:
        name: web
    spec:
      containers:
      - image: XXX/web_app
        command: ['/bin/sh', '-c']
        args: ['sudo a2enmod ssl && service apache2 restart && sudo /usr/sbin/apache2ctl -D FOREGROUND && python fake.py']
        name: web
        ports:
        - containerPort: 443
          name: http-server
        volumeMounts:
          - mountPath: /etc/letsencrypt/live/host
            name: test-volume
            readOnly: false
      volumes:
        - hostPath:
            path: /etc/letsencrypt/archive/XXX.XXX.XXX.edu
          name: test-volume

The log of the pod looks like:

root@XXX:~# kubectl logs web-controller-ontne
Considering dependency setenvif for ssl:
Module setenvif already enabled
Considering dependency mime for ssl:
Module mime already enabled
Considering dependency socache_shmcb for ssl:
Module socache_shmcb already enabled
Module ssl already enabled
 * Restarting web server apache2
[Mon Jun 27 14:34:48.753153 2016] [so:warn] [pid 30:tid 140046645868416] AH01574: module ssl_module is already loaded, skipping
   ...done.
[Mon Jun 27 14:34:49.820047 2016] [so:warn] [pid 119:tid 139909591328640] AH01574: module ssl_module is already loaded, skipping
httpd (pid 33) already running
root@XXX:~# 

The pod is running, but I got the following apache error log:

[Mon Jun 27 17:13:50.912683 2016] [ssl:warn] [pid 33:tid 140513871427456] AH01909: RSA certificate configured for 0.0.0.0i:443 does NOT include an ID which matches the server name

I think the problem is that, I am using NodePort and exposing port 30001, so I have to visit https://XXX.XXX.XXX.edu:30001 which does not match XXX.XXX.XXX.edu (just the domain name without the arbitrary port number 30001).

This is my /etc/apache2/sites-available/000-default.conf in the docker container:

<VirtualHost _default_:30001>
    DocumentRoot /usr/local/my_app

    LoadModule ssl_module /usr/lib64/apache2-prefork/mod_ssl.so
    SSLEngine on
    SSLCertificateFile /etc/letsencrypt/live/host/cert1.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/host/privkey1.pem
    SSLCertificateChainFile /etc/letsencrypt/live/host/chain1.pem

    WSGIDaemonProcess python-app user=www-data group=www-data threads=15 maximum-requests=10000 python-path=/usr/local/lib/python2.7/dist-p
ackages
    WSGIScriptAlias / /usr/local/my_app/apache/apache.wsgi
    WSGIProcessGroup python-app

    CustomLog "|/usr/bin/rotatelogs /usr/local/my_app/apache/logs/access.log.%Y%m%d-%H%M%S 5M" combined
    ErrorLog "|/usr/bin/rotatelogs /usr/local/my_app/apache/logs/error.log.%Y%m%d-%H%M%S 5M"
    LogLevel warn

    <Directory /usr/local/my_app>
        Order deny,allow
        Allow from all
        Require all granted
    </Directory>

</VirtualHost>

How to modify it so that apache serves https requests at port 30001 rather than 443? Thank you very much!

-- Yunsheng Bai
apache
docker
kubernetes

2 Answers

11/23/2016

I just run into this issue this morning.

I expose the employment using --type=NodePort I can access it from either

http://<pod ip>:<target port> 
http://<cluster IP>: <port>

But I can not access it from

  http://<Node IP>:< NodePort>

The Chrome say: .... took too long to respond

I check pod's status. It is ready and running

Later I fixed it by: delete the deployment and service.

  1. create deployment
  2. watch the pod till its status became 'running'
  3. expose this deployment using --type=NodePort

I find now the pod is running on another node. I check

 http://<new Node IP>:< new NodePort>

It works

I do not know what is the reason. Just guess:

  1. make sure the pod is created and in running status before expose the deployment
  2. maybe it is related with the cluster IP allocated by k8s
  3. maybe there is something wrong with the node machine it ever was running on.
-- Bruce Zu
Source: StackOverflow

6/29/2016

I found the answer myself. 2 causes: (1) There is an environment variable specific to my web app that I forgot to set in apache.wsgi; (2) There are several small errors in the original apache configuration file. I post the working /etc/apache2/sites-available/000-default.conf here:

ServerName 0.0.0.0

<VirtualHost _default_:443>
    DocumentRoot /usr/local/my_app

    LoadModule ssl_module /usr/lib64/apache2-prefork/mod_ssl.so
    SSLEngine on
    SSLCertificateFile /etc/letsencrypt/live/host/cert1.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/host/privkey1.pem
    SSLCertificateChainFile /etc/letsencrypt/live/host/chain1.pem

    WSGIDaemonProcess python-app user=www-data group=www-data threads=15 maximum-requests=10000 python-path=/usr/local/lib/python2.7/dist-packages
    WSGIScriptAlias / /usr/local/my_app/apache/apache.wsgi
    WSGIProcessGroup python-app

    CustomLog "|/usr/bin/rotatelogs /usr/local/my_app/apache/logs/access.log.%Y%m%d-%H%M%S 5M" combined
    ErrorLog "|/usr/bin/rotatelogs /usr/local/my_app/apache/logs/error.log.%Y%m%d-%H%M%S 5M"
    LogLevel warn

    <Directory /usr/local/my_app>
        Order deny,allow
        Allow from all
        Require all granted
    </Directory>
</VirtualHost>

Start the pod with commands sudo a2enmod ssl && sudo /usr/sbin/apache2ctl -D FOREGROUND, and containerPort should be 443. The Kubernetes script for the service is as simple as follows:

apiVersion: v1
kind: Service
metadata:
  name: web
  labels:
    name: web
spec:
  type: NodePort
  ports:
    - nodePort: 30001
      port: 443
      targetPort: 443
      protocol: TCP
  selector:
    name: web

Now I can visit my web site at https://XXX.XXX.XXX.XXX:30001.

Special thanks to the owner of this github repo and NorbertvanNobelen. Hope this helps!

-- Yunsheng Bai
Source: StackOverflow