I have followed the zero-to-binderhub guide to install jupyterhub/binderhub in GKE, but when I tried to enable https, the documentation is pretty outdated, and my final setup is not working. I document here all my steps, any help is deeply appreciated.
Just as a background, I had a working environment installed from a chart from Jun-2020. My primary reason to upgrade was the expired letsencrypt DST Root CA X3. I ended up uninstalling everything first and starting from scratch. I have 1.19.14-gke.1900 (kubectl client 1.22.3), and helm 3.5.0.
Basic http
I followed the guide, and the http installation went fine, I only had to add --create-namespace
to helm install, i.e.
helm install binderhub-dev jupyterhub/binderhub --version=0.2.0-n852.h7c39292 --namespace=binder-dev --create-namespace -f secret.yaml -f config.yaml
with the standard .yaml’s as per instructions. I get
dmoroni@cloudshell:~/binderhub2$ helm list -n=binder-dev
NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION
binderhub-dev binder-dev 2 2021-11-18 21:59:12.513460362 +0000 UTC deployed binderhub-0.2.0-n852.h7c39292
dmoroni@cloudshell:~/binderhub2 (edbr-196622)$ kubectl get svc -n=binder-dev
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
binder LoadBalancer 10.48.6.1 B1.B2.B3.B4 80:32144/TCP 2m3s
hub ClusterIP 10.48.5.244 <none> 8081/TCP 2m3s
proxy-api ClusterIP 10.48.13.133 <none> 8001/TCP 2m3s
proxy-public LoadBalancer 10.48.2.93 PP1.PP2.PP3.PP4 80:32130/TCP 2m3s
If I navigate to B1.B2.B3.B4, the standard binderhub webpage is there, and I can build and launch ok.
Setup IP
I reserved an external, static, regional, IPv4 address in GCE, let’s call it E1.E2.E3.E4. It has to be regional for the ingress-nginx to work later on.
Install cert-manager
kubectl apply -f https://github.com/jetstack/cert-manager/releases/download/v1.6.1/cert-manager.yaml
I created binderhub-issuer.yaml
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: letsencrypt-staging
namespace: binder-dev
spec:
acme:
# You must replace this email address with your own.
# Let's Encrypt will use this to contact you about expiring
# certificates, and issues related to your account.
email: <my_email>
server: https://acme-staging-v02.api.letsencrypt.org/directory
privateKeySecretRef:
# Secret resource that will be used to store the account's private key.
name: binder-dev-account-key
# Add a single challenge solver, HTTP01 using nginx
solvers:
- http01:
ingress:
class: nginx
and applied
kubectl apply -f binderhub-issuer.yaml
So far so good
dmoroni@cloudshell:~/binderhub2$ kubectl get issuer --all-namespaces
NAMESPACE NAME READY AGE
binder-dev letsencrypt-staging True 27s
Install ingress-nginx
I added the official repo, because there I can get the latest version
dmoroni@cloudshell:~/binderhub2$ helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
"ingress-nginx" has been added to your repositories
dmoroni@cloudshell:~/binderhub2$ helm repo update
Hang tight while we grab the latest from your chart repositories...
[..]
Then created ingress-nginx.yaml
controller:
service:
loadBalancerIP: E1.E2.E3.E4
and installed
helm install binderhub-proxy ingress-nginx/ingress-nginx --namespace=binder-dev -f ingress-nginx.yaml
After a minute or so
dmoroni@cloudshell:~/binderhub2$ helm list -n=binder-dev
NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION
binderhub-dev binder-dev 2 2021-11-18 21:59:12.513460362 +0000 UTC deployed binderhub-0.2.0-n852.h7c39292
binderhub-proxy binder-dev 1 2021-11-20 21:45:46.309560351 +0000 UTC deployed ingress-nginx-4.0.9 1.0.5
dmoroni@cloudshell:~/binderhub2$ kubectl get svc -n=binder-dev
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
binder LoadBalancer 10.48.6.1 B1.B2.B3.B4 80:32144/TCP 47h
binderhub-proxy-ingress-nginx-controller LoadBalancer 10.48.7.3 E1.E2.E3.E4 80:31227/TCP,443:32018/TCP 70s
binderhub-proxy-ingress-nginx-controller-admission ClusterIP 10.48.8.35 <none> 443/TCP 70s
hub ClusterIP 10.48.5.244 <none> 8081/TCP 47h
proxy-api ClusterIP 10.48.13.133 <none> 8001/TCP 47h
proxy-public LoadBalancer 10.48.2.93 PP1.PP2.PP3.PP4 80:32130/TCP 47h
Adjust binderhub
I modified my config.yaml
to:
config:
BinderHub:
use_registry: true
image_prefix: "my_organization/binder-dev-"
hub_url: https://<jupyterhub-URL>
service:
type: NodePort
jupyterhub:
proxy:
service:
type: NodePort
ingress:
enabled: true
hosts:
- <jupyterhub-URL>
annotations:
kubernetes.io/ingress.class: nginx
kubernetes.io/tls-acme: "true"
cert-manager.io/issuer: letsencrypt-staging
tls:
- secretName: <jupyterhub-URL-with-dashes-instead-of-dots>-tls
hosts:
- <jupyterhub-URL>
ingress:
enabled: true
hosts:
- <binderhub-URL>
annotations:
kubernetes.io/ingress.class: nginx
kubernetes.io/tls-acme: "true"
cert-manager.io/issuer: letsencrypt-staging
tls:
- secretName: <binderhub-URL-with-dashes-instead-of-dots>-tls
hosts:
- <binderhub-URL>
and to be clear, <binderhub-URL>
points to E1.E2.E3.E4, and that’s where I expect the https version of the binderhub webpage to be. Instead <jupyterhub-URL>
points to a different IP and that’s where I expect my kernels to be spawned.
The secret.yaml
is unchanged. Then:
dmoroni@cloudshell:~/binderhub2$ helm upgrade binderhub-dev jupyterhub/binderhub --version=0.2.0-n852.h7c39292 --namespace=binder-dev -f secret.yaml -f config.yaml
Release "binderhub-dev" has been upgraded. Happy Helming!
[..]
Check:
dmoroni@cloudshell:~/binderhub2$ kubectl get svc -n=binder-dev
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
binder NodePort 10.48.6.1 <none> 80:32144/TCP 2d1h
binderhub-proxy-ingress-nginx-controller LoadBalancer 10.48.7.3 E1.E2.E3.E4 80:31227/TCP,443:32018/TCP 105m
binderhub-proxy-ingress-nginx-controller-admission ClusterIP 10.48.8.35 <none> 443/TCP 105m
cm-acme-http-solver-4z94c NodePort 10.48.6.198 <none> 8089:32231/TCP 21m
hub ClusterIP 10.48.5.244 <none> 8081/TCP 2d1h
proxy-api ClusterIP 10.48.13.133 <none> 8001/TCP 2d1h
proxy-public NodePort 10.48.2.93 <none> 80:32130/TCP 2d1h
dmoroni@cloudshell:~/binderhub2$ kubectl get certificates --all-namespaces
NAMESPACE NAME READY SECRET AGE
binder-dev <binderhub>-tls True <binderhub>-tls 22m
binder-dev <jupyterhub>-tls False <jupyterhub>-tls 22m
dmoroni@cloudshell:~/binderhub2$ kubectl describe certificate <jupyterhub>-tls -n=binder-dev
Name: <jupyterhub>-tls
Namespace: binder-dev
Labels: app=jupyterhub
app.kubernetes.io/managed-by=Helm
chart=jupyterhub-1.1.2
component=ingress
heritage=Helm
release=binderhub-dev
Annotations: <none>
API Version: cert-manager.io/v1
Kind: Certificate
Metadata:
[..]
Spec:
Dns Names:
<jupyterhub-URL>
Issuer Ref:
Group: cert-manager.io
Kind: Issuer
Name: letsencrypt-staging
Secret Name: <jupyterhub>-tls
Usages:
digital signature
key encipherment
Status:
Conditions:
Last Transition Time: 2021-11-20T23:09:04Z
Message: Issuing certificate as Secret does not exist
Observed Generation: 1
Reason: DoesNotExist
Status: False
Type: Ready
Last Transition Time: 2021-11-20T23:09:04Z
Message: Issuing certificate as Secret does not exist
Observed Generation: 1
Reason: DoesNotExist
Status: True
Type: Issuing
Next Private Key Secret Name: <jupyterhub>-tls-q89qd
Events: <none>
Results
The webpage is reachable but with a NET::ERR_CERT_AUTHORITY_INVALID, while is not reachable.
What is going on?