jupyterhub的分布式搭建-基于kubernetes的jupyterhub

jupyterhub分布式搭建

注意:以下操作均以系统管理员root执行的


一. kubernetes集群搭建

  • 更改hostname
# 在 master 节点和 worker 节点都执行
hostnamectl set-hostname master
  • 卸载旧版本
# 在 master 节点和 worker 节点都执行
yum remove -y docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-selinux \
docker-engine-selinux \
docker-engine
  • 设置yum respository
# 在 master 节点和 worker 节点都执行
yum install -y yum-utils \
device-mapper-persistent-data \
lvm2
sudo yum-config-manager \
--add-repo \
https://download.docker.com/linux/centos/docker-ce.repo
  • 安装并启动docker(若遇到下载较慢,则把那个较慢的文件下载下来手动安装)
# 在 master 节点和 worker 节点都执行
yum install -y docker-ce-18.09.7 docker-ce-cli-18.09.7 containerd.io
systemctl enable docker
systemctl start docker
  • 检查docker版本
# 在 master 节点和 worker 节点都执行
docker version

参考文档:

https://docs.docker.com/install/linux/docker-ce/centos/

https://docs.docker.com/install/linux/linux-postinstall/

  • 安装 nfs-utils
# 在 master 节点和 worker 节点都执行
yum install -y nfs-utils
  • 配置k8s的yum源
# 在 master 节点和 worker 节点都执行
cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=http://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=0
repo_gpgcheck=0
gpgkey=http://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg
       http://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF
  • 关闭 防火墙、SeLinux、swap
# 在 master 节点和 worker 节点都要执行
systemctl stop firewalld
systemctl disable firewalld

setenforce 0
sed -i "s/SELINUX=enforcing/SELINUX=disabled/g" /etc/selinux/config

swapoff -a
yes | cp /etc/fstab /etc/fstab_bak
cat /etc/fstab_bak |grep -v swap > /etc/fstab
  • 修改 /etc/sysctl.conf
# 在 master 节点和 worker 节点都要执行
vim /etc/sysctl.conf

向其中添加

net.ipv4.ip_forward = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1

执行命令使添加生效

# 在 master 节点和 worker 节点都要执行
sysctl -p
  • 安装kubelet、kubeadm、kubectl
# 在 master 节点和 worker 节点都要执行
yum install -y kubelet-1.15.1 kubeadm-1.15.1 kubectl-1.15.1
  • 修改/usr/lib/systemd/system/docker.service
# 在 master 节点和 worker 节点都要执行
vim /usr/lib/systemd/system/docker.service

向其中添加

--exec-opt native.cgroupdriver=systemd

添加位置参考下图

在这里插入图片描述

  • 执行以下命令使用 docker 国内镜像,提高 docker 镜像下载速度和稳定性
# 在 master 节点和 worker 节点都要执行
curl -sSL https://get.daocloud.io/daotools/set_mirror.sh | sh -s http://f1361db2.m.daocloud.io
  • 重启docker, 并启动kubectl
# 在 master 节点和 worker 节点都要执行
systemctl daemon-reload
systemctl restart docker
systemctl enable kubelet && systemctl start kubelet
  • 配置 master 的域名
# 只在 master 节点执行
echo "x.x.x.x  master" >> /etc/hosts
  • 创建 ./kubeadm-config.yaml
# 只在 master 节点执行
cat <<EOF > ./kubeadm-config.yaml
apiVersion: kubeadm.k8s.io/v1beta1
kind: ClusterConfiguration
kubernetesVersion: v1.15.1
imageRepository: registry.cn-hangzhou.aliyuncs.com/google_containers
controlPlaneEndpoint: "master:6443"
networking:
  podSubnet: "10.100.0.1/20"
EOF

注意podSubnet所使用的网段不能与节点所在的网段重叠

  • 初始化 master
# 只在 master 节点执行
kubeadm init --config=kubeadm-config.yaml --upload-certs

根据自身服务器情况等待几分钟,执行成功结果如图:

在这里插入图片描述

  • 初始化 root 用户的 kubectl 配置
# 只在 master 节点执行
rm -rf /root/.kube/
mkdir /root/.kube/
cp -i /etc/kubernetes/admin.conf /root/.kube/config
  • 安装 calico
# 只在 master 节点执行
kubectl apply -f https://docs.projectcalico.org/v3.6/getting-started/kubernetes/installation/hosted/kubernetes-datastore/calico-networking/1.7/calico.yaml

安装calico,可参考https://docs.projectcalico.org/v3.6/getting-started/kubernetes/

  • 执行以下命令,等待3-10分钟,直到所有的容器储与Running状态
# 只在 master 节点执行
watch kubectl get pod -n kube-system
  • 检查 master 初始化结果
# 只在 master 节点执行
kubectl get nodes
  • 获得join参数
# 只在 master 节点执行
kubeadm token create --print-join-command

输入以上命令获得的结果如下

# kubeadm token create 命令的输出
kubeadm join master:6443 --token mpfjma.4vjjg8flqihor4vt     --discovery-token-ca-cert-hash sha256:6f7a8e40a810323672de5eee6f4d19aa2dbdb38411845a1bf5dd63485c43d303
  • 针对所有的 worker 节点执行
# 只在 worker 节点执行
echo "x.x.x.x  master" >> /etc/hosts
kubeadm join apiserver.demo:6443 --token mpfjma.4vjjg8flqihor4vt     --discovery-token-ca-cert-hash sha256:6f7a8e40a810323672de5eee6f4d19aa2dbdb38411845a1bf5dd63485c43d303

需要将x.x.x.x替换为master节点的IP,下面一行命令为“获得join”参数后的输出

  • 检查初始化结果
# 只在 master 节点执行
kubectl get nodes

在这里插入图片描述

  • 安装Ingress Controller(可不做)
# 只在 master 节点执行
kubectl apply -f https://raw.githubusercontent.com/eip-work/eip-monitor-repository/master/dashboard/nginx-ingress.yaml

Ingress官方文档:https://kubernetes.io/docs/concepts/services-networking/ingress/

Ingress Controllers官网介绍:https://kubernetes.io/docs/concepts/services-networking/ingress-controllers/

本文中使用如下部署方式:https://kubernetes.github.io/ingress-nginx/deploy/baremetal/#using-a-self-provisioned-edge

kubernetes支持多种Ingress Controllers,本文推荐使用 https://github.com/nginxinc/kubernetes-ingress

  • 配置域名解析(目前不需要做)

将域名 *.demo.yourdomain.com 解析到 demo-worker-a-2 的 IP 地址 z.z.z.z (也可以是 demo-worker-a-1 的地址 y.y.y.y)

验证配置

在浏览器访问 a.demo.yourdomain.com,将得到 404 NotFound 错误页面

由于需要申请域名,过程会比较繁琐,有如下两种替代方案:

  • 在您的客户端机器(访问部署在K8S上的 web 应用的浏览器所在的机器)设置 hosts 配置;
  • 暂时放弃域名的配置,临时使用 NodePort 或者 kubectl port-forward 的方式访问部署在 K8S 上的 web 应用

如果您打算将您安装的 Kubernetes 用于生产环境,请参考此文档 Installing Ingress Controller,完善 Ingress 的配置


到此 kubernetes 集群已全部安装完毕,下面为worker节点出错使一出worker节点的方法

  • 在准备移除的 worker 节点上执行
# 只在 worker 节点执行
kubeadm reset
  • 在 master 节点上执行
# 只在 master 节点执行
kubectl delete node demo-worker-x-x

二. k8s集群监控软件Kuboard的安装

  • 安装kuboard
# 在 master 节点执行
kubectl apply -f https://kuboard.cn/install-script/kuboard.yaml
  • 查看kuboard状态
# 在 master 节点执行
kubectl get pods -l k8s.eip.work/name=kuboard -n kube-system

输出结果如下:

NAME                       READY   STATUS        RESTARTS   AGE
kuboard-54c9c4f6cb-6lf88   1/1     Running       0          45s
  • 获取管理员用户的token
# 如果您参考 www.kuboard.cn 提供的文档安装 Kuberenetes,可在第一个 Master 节点上执行此命令
kubectl -n kube-system describe secret $(kubectl -n kube-system get secret | grep kuboard-user | awk '{print $1}')   

输出示例:

Name: admin-user-token-g8hxb
Namespace: kube-system
Labels: <none>
Annotations: [kubernetes.io/service-account.name](http://kubernetes.io/service-account.name): Kuboard-user
[kubernetes.io/service-account.uid](http://kubernetes.io/service-account.uid): 948bb5e6-8cdc-11e9-b67e-fa163e5f7a0f

Type: [kubernetes.io/service-account-token](http://kubernetes.io/service-account-token)

Data
====
ca.crt: 1025 bytes
namespace: 11 bytes
token: eyJhbGciOiJSUzI1NiIsImtpZCI6IiJ9.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJhZG1pbi11c2VyLXRva2VuLWc4aHhiIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQubmFtZSI6ImFkbWluLXVzZXIiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC51aWQiOiI5NDhiYjVlNi04Y2RjLTExZTktYjY3ZS1mYTE2M2U1ZjdhMGYiLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6a3ViZS1zeXN0ZW06YWRtaW4tdXNlciJ9.DZ6dMTr8GExo5IH_vCWdB_MDfQaNognjfZKl0E5VW8vUFMVvALwo0BS-6Qsqpfxrlz87oE9yGVCpBYV0D00811bLhHIg-IR_MiBneadcqdQ_TGm_a0Pz0RbIzqJlRPiyMSxk1eXhmayfPn01upPdVCQj6D3vAY77dpcGplu3p5wE6vsNWAvrQ2d_V1KhR03IB1jJZkYwrI8FHCq_5YuzkPfHsgZ9MBQgH-jqqNXs6r8aoUZIbLsYcMHkin2vzRsMy_tjMCI9yXGiOqI-E5efTb-_KbDVwV5cbdqEIegdtYZ2J3mlrFQlmPGYTwFI8Ba9LleSYbCi4o0k74568KcN_w
  • 访问kuboard,默认端口为32567
http://任意一个Worker节点的IP地址:32567/

以下为获取只读用户以及其它访问方式的附属文档

  • 获取只读用户token
# 如果您参考 www.kuboard.cn 提供的文档安装 Kuberenetes,可在第一个 Master 节点上执行此命令
kubectl -n kube-system describe secret $(kubectl -n kube-system get secret | grep kuboard-viewer | awk '{print $1}')   

只读用户拥有的权限:

(1):view 可查看名称空间的内容

(2):system:node 可查看节点信息

(3):system:persistent-volume-provisioner 可查看存储类和存储卷声明的信息

适用场景:

只读用户不能对集群的配置执行修改操作,非常适用于将开发环境中的 Kuboard 只读权限分发给开发者,以便开发者可以便捷地诊断问题

  • 通过port-forward访问kuboard
# 在 master 节点执行
kubectl port-forward service/kuboard 8080:80 -n kube-system

在浏览器打开连接
http://x.x.x.x:8080


三. Helm的安装

  • 访问 https://github.com/kubernetes/helm/releases 下载合适的helm版本,此处下载的为 helm-v2.16.1-linux-amd64.tar.gz
  • 解压文件
# 在master节点执行
tar -zxvf helm-v2.16.1-linux-amd64.tar.gz
  • 将解压后的helm移动到/usr/local/bin目录下:
# 在master节点执行
mv linux-amd64/helm /usr/local/bin/helm
  • 安装socat
# 在master和worker节点执行
yum install -y socat 

否则可能会报如下错误

Error: cannot connect to Tiller
  • 创建一个名为tiller的Service Account
# 在 master 节点执行
kubectl create serviceaccount tiller --namespace kube-system
  • 授予名未tiller的Service Account集群管理员角色cluster-admin,首先创建名为rbac-config.yaml
apiVersion: rbac.authorization.k8s.io/v1beta1 
kind: ClusterRoleBinding 
metadata: 
  name: tiller 
roleRef: 
  apiGroup: rbac.authorization.k8s.io 
  kind: ClusterRole 
  name: cluster-admin 
subjects: 
- kind: ServiceAccount 
  name: tiller 
  namespace: kube-system
  • 绑定授予tiller集群管理员
# 在 master 节点执行
kubectl create -f rbac-config.yaml
  • 安装Tiller服务器
# 在 master 节点执行
helm init --service-account tiller
  • 验证安装
# 在 master 节点执行
helm version

若正确显示Helm客户端和Tiller服务器的版本,表示安装成功

若出现 cannot connect to Tiller 或者 could not find a ready tiller pod 的问题,输入以下命令:

# 在 master 节点执行
helm init -i sapcc/tiller:v2.16.1 --upgrade
  • 设置添加tiller账户
# 在 master 节点执行
kubectl --namespace kube-system patch deploy tiller-deploy -p '{"spec":{"template":{"spec":{"serviceAccount":"tiller"}}}}'

四. nfs服务的安装配置

  • 在所有节点安装nfs
# 在 master 和 worker 节点执行
yum install -y nfs-common nfs-utils 
  • 创建共享目录
# 在 master 节点执行
mkdir /nfsdata
  • 授权共享目录
# 在 master 节点执行
chmod 666 /nfsdata
  • 编辑nfs的配置文件:/etc/exports
# 在 master 节点执行
vim /etc/exports
/nfsdata *(rw,no_root_squash,no_all_squash,sync)

说明:

/nfsdata:是共享数据的目录。

*:表示任何人都有权限连接。

rw:读写的权限

sync:表示文件同时写入硬盘和内存

no_root_squash:当登录 NFS 主机使用共享目录的使用者是 root 时,其权限将被转换成为匿名使用者,通常它的 UID 与 GID,都会变成 nobody 身份

  • 启动rpc 和 nfs(注意启动的顺序)
# 在 master 节点执行

#先启动rpc
systemctl start rpcbind.service
systemctl enable rpcbind
systemctl status rpcbind

# 再启动nfs
systemctl start nfs.service
systemctl enable nfs
systemctl status nfs
  • 确认nfs安装成功
# 在 master 节点执行
rpcinfo -p|grep nfs

输出示例:

100003    3   tcp   2049  nfs
100003    4   tcp   2049  nfs
100227    3   tcp   2049  nfs_acl
100003    3   udp   2049  nfs
100003    4   udp   2049  nfs
100227    3   udp   2049  nfs_acl
  • 查看目录的挂载权限
# 在 master 节点执行
cat /var/lib/nfs/etab

输出示例:

/data/k8s    *(rw,sync,wdelay,hide,nocrossmnt,secure,no_root_squash,no_all_squash,no_subtree_check,secure_locks,acl,no_pnfs,anonuid=65534,anongid=65534,sec=sys,secure,no_root_squash,no_all_squash)

以下为在work节点验证nfs服务是否互通,可不做

  • 安装 nfs
# 在 work 节点执行
yum -y install nfs-utils rpcbind
  • 启动 rpc 和 nfs (注意顺序)
# 在 work 节点执行
systemctl start rpcbind.service
systemctl enable rpcbind.service 
systemctl start nfs.service 
systemctl enable nfs.service
  • 检查 nfs 是否有共享目录
# 在 work 节点执行
showmount -e master

输出示例:

Export list for master:
/nfsdata *
  • 在 work 节点新建目录:
# 在 worker 节点执行
mkdir -p /root/course/kubeadm/data
  • 将 nfs 共享目录挂载到上面的目录:
# 在 worker 节点执行
mount -t nfs master:/nfsdata /root/course/kubeadm/data
  • 在 work 节点上面的目录中新建测试文件
# 在 worker 节点执行
touch /root/course/kubeadm/data/test.txt
  • 在 nfs 服务器端查看:
# 在 master 节点执行
ls -ls /nfsdata

若上面出现了test.txt 文件,那么就证明我们的 nfs 挂载成功了


五. storageclass的建立

  • 配置 deployment (nfs-client.yaml)
kind: Deployment
apiVersion: extensions/v1beta1
metadata:
  name: nfs-client-provisioner
spec:
  replicas: 1
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: nfs-client-provisioner
    spec:
      serviceAccountName: nfs-client-provisioner
      containers:
        - name: nfs-client-provisioner
          image: quay.io/external_storage/nfs-client-provisioner:latest
          volumeMounts:
            - name: nfs-client-root
              mountPath: /persistentvolumes
          env:
            - name: PROVISIONER_NAME
              value: fuseim.pri/ifs
            - name: NFS_SERVER
              value: 172.16.1.8 #替换IP
            - name: NFS_PATH
              value: /nfsdata
      volumes:
        - name: nfs-client-root
          nfs:
            server: 172.16.1.8 #替换IP
            path: /nfsdata

注意替换自己的IP

  • 配置 Service Account ,绑定对应权限 (nfs-client-sa.yaml)
apiVersion: v1
kind: ServiceAccount
metadata:
  name: nfs-client-provisioner

---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: nfs-client-provisioner-runner
rules:
  - apiGroups: [""]
    resources: ["persistentvolumes"]
    verbs: ["get", "list", "watch", "create", "delete"]
  - apiGroups: [""]
    resources: ["persistentvolumeclaims"]
    verbs: ["get", "list", "watch", "update"]
  - apiGroups: ["storage.k8s.io"]
    resources: ["storageclasses"]
    verbs: ["get", "list", "watch"]
  - apiGroups: [""]
    resources: ["events"]
    verbs: ["list", "watch", "create", "update", "patch"]
  - apiGroups: [""]
    resources: ["endpoints"]
    verbs: ["create", "delete", "get", "list", "watch", "patch", "update"]

---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: run-nfs-client-provisioner
subjects:
  - kind: ServiceAccount
    name: nfs-client-provisioner
    namespace: default
roleRef:
  kind: ClusterRole
  name: nfs-client-provisioner-runner
  apiGroup: rbac.authorization.k8s.io
  • 创建 StorageClass (nfs-client-class.yaml)
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: course-nfs-storage
provisioner: fuseim.pri/ifs # or choose another name, must match deployment's env PROVISIONER_NAME'
  • 创建 /persistentvolumes 目录并赋予相关权限
# 在 master 节点执行
mkdir /persistentvolumes
chmod 666 /persistentvolumes
  • 创建刚才写的资源对象
# 在 master 节点执行
kubectl create -f nfs-client.yaml
kubectl create -f nfs-client-sa.yaml
kubectl create -f nfs-client-class.yaml
  • 查看资源状态
# 在 master 节点执行
kubectl get pods

输出示例:

在这里插入图片描述

  • 将 course-nfs-storage 设为默认的StorageClass
# 在 master 节点执行
kubectl patch storageclass course-nfs-storage -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'

六. jupyterhub的安装

  • 生成随机安全令牌
# 在 master 节点执行
openssl rand -hex 32
  • 编辑 config.yaml 文件
proxy:
  secretToken: "xxxxxxxxxxxxxxx"
  • helm更新安装jupyterhub的chart repository
# 在 master 节点执行
helm repo add jupyterhub https://jupyterhub.github.io/helm-chart/
helm repo update

输出示例:

Hang tight while we grab the latest from your chart repositories...
...Skip local chart repository
...Successfully got an update from the "stable" chart repository
...Successfully got an update from the "jupyterhub" chart repository
Update Complete.
  • 安装chart configured
# 在 master 节点执行
helm upgrade --install jhub jupyterhub/jupyterhub \
--namespace jhub  \
--version=0.8.2 \
--values config.yaml

注意直接执行即可无需改动

注意下面步骤非常重要

  • 在执行上面命令后会发现界面一直卡在如下所示不动

在这里插入图片描述

  • 此时打开另一个 master 窗口,查看pod
# 在master节点执行
kubectl get pod --namespace jhub

发现报 ErrImagePull 错,如下图所示:

在这里插入图片描述

  • 此时通过如下命令修改这个pod
# 在 master 节点执行
kubectl edit pod hook-image-puller-p9j9b -n jhub

将该文件中的 gcr.io 全部替换为 gcr.azk8s.cn ,再保存退出

  • 稍等一会,在原窗口可以看到如下界面:

在这里插入图片描述

  • 此时再次查看 jhub 命名空间的pod
# 在 master 节点执行
kubectl get pod --namespace jhub

出现如下这表示成功:

在这里插入图片描述

  • 查看service
# 在 master 节点执行
kubectl get service --namespace jhub

此时发现 proxy-public 的 EXTERNAL-IP 处于pending状态

在这里插入图片描述

  • 修改proxy-public
# 在 master 节点执行
kubectl edit service proxy-public -n jhub

将 type: LoadBalancer 改成 type: NodePort

  • 再次查看 service

在这里插入图片描述

此时我们在浏览器中通过 80 映射的端口去访问jupyterhub

在这里插入图片描述

  • 此时由于jupyterhub是默认设置任何用户均可登陆

在这里插入图片描述

  • 到此,基于k8s的jupyterhub已经全部搭建完成。

后记 2020.6.30

  • 这篇文章写于去年,当时小白一枚,接了领导的任务去研究jupyterhub 的分布式搭建。当时对 k8s 这个词都不了解。。。 在搭建的途中也踩了很多坑,主要还是吃了没有系统学习k8s的亏。。。 现在看来,这里面其实就是搭建了个 k8s 集群,然后建了个 nfs 用作 k8s 的存储,安了个 storageclass 用于自动生成 pv ,然后在利用 helm 安装 jupyterhub ,等这些步骤。
  • 由于时效的原因,现在看这篇文章可能有些老了,一些方法可能由于版本的跟新不能用了,建议大家如果时间不急的话还是先初略的了解一遍 k8s 相关知识,这样就会轻松许多。附上我学习 k8s 时看的文章,个人感觉通俗易懂,非常适合小白入门。https://www.qikqiak.com/k8s-book/
  • 其实juyterhub 到这里只能算是基本能用,还有很多功能是需要探索的,比如说 使用界面更加友好的jupyterlab 来替换原始的 notebook,使用自定义的数据库去管理登录的用户(比如mysql),添加自定义的环境等等,这里面涉及到对原始镜像的改造,这就需要更加深入的对k8s 和 容器的理解了,这些在我时间充裕的时候大概会写一点吧,敬请期待。
  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 14
    评论
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值