热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

在Kubernetes上部署JupyterHub的步骤和实验依赖

本文介绍了在Kubernetes上部署JupyterHub的步骤和实验所需的依赖,包括安装Docker和K8s,使用kubeadm进行安装,以及更新下载的镜像等。



理论是灰色的,实践之树长青🌲 ——恩格斯





近日在做毕设项目,涉及到在K8s和swarm基础上部署JupyterHub,经过两天时间的学习和部署,N次的失败尝试,最终在服务器上成功部署了JupyterHub!



实验依赖


  • 阿里云服务器2核4G - ubuntu18.04 (服务器至少2核)
  • Docker v20.10.5
  • K8s v1.20.5
  • Helm v3.5.2

step1:安装Docker

curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun

step2:安装k8s


因为我们需要在k8s上安装Jupyterhub,所以需要安装k8s,k8s有多种安装方式,在这里我们使用kubeadm进行安装。



1、镜像替换更新


由于众所周知强的问题,所以这里需要更新一下下载的镜像,使用如下命令:


apt-get update && apt-get install -y apt-transport-https
curl -s https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg | apt-key add -
cat <<EOF >/etc/apt/sources.list.d/kubernetes.list
deb https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main
EOF
apt-get update

2、安装 kubeadm, kubelet and kubectl

root&#64;host1:~# apt-get install -y kubelet kubeadm kubectl
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following additional packages will be installed:conntrack cri-tools kubernetes-cni socat
The following NEW packages will be installed:conntrack cri-tools kubeadm kubectl kubelet kubernetes-cni socat
0 upgraded, 7 newly installed, 0 to remove and 88 not upgraded.
Need to get 68.7 MB of archives.
After this operation, 293 MB of additional disk space will be used.
Get:1 https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main amd64 cri-tools amd64 1.13.0-01 [8,775 kB]
Get:2 http://archive.ubuntu.com/ubuntu bionic/main amd64 conntrack amd64 1:1.4.4&#43;snapshot20161117-6ubuntu2 [30.6 kB]
Get:3 http://archive.ubuntu.com/ubuntu bionic/main amd64 socat amd64 1.7.3.2-2ubuntu2 [342 kB]
Get:4 https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main amd64 kubernetes-cni amd64 0.8.7-00 [25.0 MB]
Get:5 https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main amd64 kubelet amd64 1.20.5-00 [18.9 MB]
Get:6 https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main amd64 kubectl amd64 1.20.5-00 [7,945 kB]
Get:7 https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main amd64 kubeadm amd64 1.20.5-00 [7,709 kB]
Fetched 68.7 MB in 51s (1,360 kB/s)
Selecting previously unselected package conntrack.
(Reading database ... 111595 files and directories currently installed.)
Preparing to unpack .../0-conntrack_1%3a1.4.4&#43;snapshot20161117-6ubuntu2_amd64.deb ...
Unpacking conntrack (1:1.4.4&#43;snapshot20161117-6ubuntu2) ...
Selecting previously unselected package cri-tools.
Preparing to unpack .../1-cri-tools_1.13.0-01_amd64.deb ...
Unpacking cri-tools (1.13.0-01) ...
Selecting previously unselected package kubernetes-cni.
Preparing to unpack .../2-kubernetes-cni_0.8.7-00_amd64.deb ...
Unpacking kubernetes-cni (0.8.7-00) ...
Selecting previously unselected package socat.
Preparing to unpack .../3-socat_1.7.3.2-2ubuntu2_amd64.deb ...
Unpacking socat (1.7.3.2-2ubuntu2) ...
Selecting previously unselected package kubelet.
Preparing to unpack .../4-kubelet_1.20.5-00_amd64.deb ...
Unpacking kubelet (1.20.5-00) ...
Selecting previously unselected package kubectl.
Preparing to unpack .../5-kubectl_1.20.5-00_amd64.deb ...
Unpacking kubectl (1.20.5-00) ...
Selecting previously unselected package kubeadm.
Preparing to unpack .../6-kubeadm_1.20.5-00_amd64.deb ...
Unpacking kubeadm (1.20.5-00) ...
Setting up conntrack (1:1.4.4&#43;snapshot20161117-6ubuntu2) ...
Setting up kubernetes-cni (0.8.7-00) ...
Setting up cri-tools (1.13.0-01) ...
Setting up socat (1.7.3.2-2ubuntu2) ...
Setting up kubelet (1.20.5-00) ...
Created symlink /etc/systemd/system/multi-user.target.wants/kubelet.service → /lib/systemd/system/kubelet.service.
Setting up kubectl (1.20.5-00) ...
Setting up kubeadm (1.20.5-00) ...
Processing triggers for man-db (2.8.3-2ubuntu0.1) ...

3、使用 kubeadm 创建 Kubernetes 集群

# 确保关闭交换空间
$ sudo swapoff -a# 获取最新 Kubernetes 版本号
$ KUBERNETES_RELEASE_VERSION&#61;"$(curl -sSL https://dl.k8s.io/release/stable.txt)"# 可以用下面的命令列出 kubeadm 需要的 images
$ kubeadm config images list --kubernetes-version&#61;${KUBERNETES_RELEASE_VERSION}
# 所需版本如下&#xff08;每个人情况可能不同&#xff0c;以自己的结果为主&#xff09;
root&#64;host1:~# kubeadm config images list --kubernetes-version&#61;${KUBERNETES_RELEASE_VERSION}
k8s.gcr.io/kube-apiserver:v1.20.5
k8s.gcr.io/kube-controller-manager:v1.20.5
k8s.gcr.io/kube-scheduler:v1.20.5
k8s.gcr.io/kube-proxy:v1.20.5
k8s.gcr.io/pause:3.2
k8s.gcr.io/etcd:3.4.13-0
k8s.gcr.io/coredns:1.7.0

由于墙的问题&#xff0c;我们不能将这些image拉下来&#xff0c;所以在这里我们采用脚本的方式将其下载&#xff1b;
编写脚本k8sInstall.py下载所需镜像,注意&#xff0c;脚本中的版本号要和kubeadm config images list命令显示的版本号一致&#xff0c;脚本文件如下&#xff1a;


// k8sInstall.py
#! /usr/bin/python3import osimages&#61;["kube-apiserver:v1.20.5","kube-controller-manager:v1.20.5","kube-scheduler:v1.20.5","kube-proxy:v1.20.5","pause:3.2","etcd:3.4.13-0","coredns:1.7.0",
]for i in images:pullCMD &#61; "docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/{}".format(i)print("run cmd &#39;{}&#39;, please wait ...".format(pullCMD))os.system(pullCMD)tagCMD &#61; "docker tag registry.cn-hangzhou.aliyuncs.com/google_containers/{} k8s.gcr.io/{}".format(i, i)print("run cmd &#39;{}&#39;, please wait ...".format(tagCMD ))os.system(tagCMD)rmiCMD &#61; "docker rmi registry.cn-hangzhou.aliyuncs.com/google_containers/{}".format(i)print("run cmd &#39;{}&#39;, please wait ...".format(rmiCMD ))os.system(rmiCMD)# 执行脚本文件&#xff0c;下载镜像
root&#64;host1:~# vim k8sInstall.py
root&#64;host1:~# chmod 775 k8sInstall.py
root&#64;host1:~# sudo ./k8sInstall.py
run cmd &#39;docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/kube-apiserver:v1.20.5&#39;, please wait ...
v1.20.5: Pulling from google_containers/kube-apiserver
fefd475334af: Pull complete
742efefc8a44: Pull complete
98d681774b17: Pull complete
Digest: sha256:e2ca052cbde8532d4c2e613a7fbb3145a5ecbea1bd47ac243877815ed80abb5a
Status: Downloaded newer image for registry.cn-hangzhou.aliyuncs.com/google_containers/kube-apiserver:v1.20.5
registry.cn-hangzhou.aliyuncs.com/google_containers/kube-apiserver:v1.20.5
run cmd &#39;docker tag registry.cn-hangzhou.aliyuncs.com/google_containers/kube-apiserver:v1.20.5 k8s.gcr.io/kube-apiserver:v1.20.5&#39;, please wait ...
run cmd &#39;docker rmi registry.cn-hangzhou.aliyuncs.com/google_containers/kube-apiserver:v1.20.5&#39;, please wait ...
Untagged: registry.cn-hangzhou.aliyuncs.com/google_containers/kube-apiserver:v1.20.5
Untagged: registry.cn-hangzhou.aliyuncs.com/google_containers/kube-apiserver&#64;sha256:e2ca052cbde8532d4c2e613a7fbb3145a5ecbea1bd47ac243877815ed80abb5a
run cmd &#39;docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/kube-controller-manager:v1.20.5&#39;, please wait ...
v1.20.5: Pulling from google_containers/kube-controller-manager
fefd475334af: Already exists
742efefc8a44: Already exists
454a7944c47b: Pull complete
Digest: sha256:ddba11d3205b4fde9b8621b79bbb942f1d0797ffcc9dfb72d197b0c84943e369
Status: Downloaded newer image for registry.cn-hangzhou.aliyuncs.com/google_containers/kube-controller-manager:v1.20.5
......

4、集群初始化


服务器必须是2核及以上&#xff0c;否则在这一步会出现问题&#xff01;&#xff01;&#xff01;


root&#64;host1:~# kubeadm init --ignore-preflight-errors&#61;SystemVerification
[init] Using Kubernetes version: v1.20.5
[preflight] Running pre-flight checks[WARNING IsDockerSystemdCheck]: detected "cgroupfs" as the Docker cgroup driver. The recommended driver is "systemd". Please follow the guide at https://kubernetes.io/docs/setup/cri/[WARNING SystemVerification]: this Docker version is not on the list of validated versions: 20.10.5. Latest validated version: 19.03
[preflight] Pulling images required for setting up a Kubernetes cluster
[preflight] This might take a minute or two, depending on the speed of your internet connection
[preflight] You can also perform this action in beforehand using &#39;kubeadm config images pull&#39;
[certs] Using certificateDir folder "/etc/kubernetes/pki"
[certs] Generating "ca" certificate and key
[certs] Generating "apiserver" certificate and key
[certs] apiserver serving cert is signed for DNS names [izwz9hwh629hd38je8xvscz kubernetes kubernetes.default kubernetes.default.svc kubernetes.default.svc.cluster.local] and IPs [10.96.0.1 172.21.24.197]
[certs] Generating "apiserver-kubelet-client" certificate and key
[certs] Generating "front-proxy-ca" certificate and key
[certs] Generating "front-proxy-client" certificate and key
[certs] Generating "etcd/ca" certificate and key
[certs] Generating "etcd/server" certificate and key
[certs] etcd/server serving cert is signed for DNS names [izwz9hwh629hd38je8xvscz localhost] and IPs [172.21.24.197 127.0.0.1 ::1]
[certs] Generating "etcd/peer" certificate and key
[certs] etcd/peer serving cert is signed for DNS names [izwz9hwh629hd38je8xvscz localhost] and IPs [172.21.24.197 127.0.0.1 ::1]
[certs] Generating "etcd/healthcheck-client" certificate and key
[certs] Generating "apiserver-etcd-client" certificate and key
[certs] Generating "sa" key and public key
[kubeconfig] Using kubeconfig folder "/etc/kubernetes"
[kubeconfig] Writing "admin.conf" kubeconfig file
[kubeconfig] Writing "kubelet.conf" kubeconfig file
[kubeconfig] Writing "controller-manager.conf" kubeconfig file
[kubeconfig] Writing "scheduler.conf" kubeconfig file
[kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env"
[kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml"
[kubelet-start] Starting the kubelet
[control-plane] Using manifest folder "/etc/kubernetes/manifests"
[control-plane] Creating static Pod manifest for "kube-apiserver"
[control-plane] Creating static Pod manifest for "kube-controller-manager"
[control-plane] Creating static Pod manifest for "kube-scheduler"
[etcd] Creating static Pod manifest for local etcd in "/etc/kubernetes/manifests"
[wait-control-plane] Waiting for the kubelet to boot up the control plane as static Pods from directory "/etc/kubernetes/manifests". This can take up to 4m0s
[kubelet-check] Initial timeout of 40s passed.
[apiclient] All control plane components are healthy after 85.005388 seconds
[upload-config] Storing the configuration used in ConfigMap "kubeadm-config" in the "kube-system" Namespace
[kubelet] Creating a ConfigMap "kubelet-config-1.20" in namespace kube-system with the configuration for the kubelets in the cluster
[upload-certs] Skipping phase. Please see --upload-certs
[mark-control-plane] Marking the node izwz9hwh629hd38je8xvscz as control-plane by adding the labels "node-role.kubernetes.io/master&#61;&#39;&#39;" and "node-role.kubernetes.io/control-plane&#61;&#39;&#39; (deprecated)"
[mark-control-plane] Marking the node izwz9hwh629hd38je8xvscz as control-plane by adding the taints [node-role.kubernetes.io/master:NoSchedule]
[bootstrap-token] Using token: 33wev0.vwvmk139exv3ohx3
[bootstrap-token] Configuring bootstrap tokens, cluster-info ConfigMap, RBAC Roles
[bootstrap-token] configured RBAC rules to allow Node Bootstrap tokens to get nodes
[bootstrap-token] configured RBAC rules to allow Node Bootstrap tokens to post CSRs in order for nodes to get long term certificate credentials
[bootstrap-token] configured RBAC rules to allow the csrapprover controller automatically approve CSRs from a Node Bootstrap Token
[bootstrap-token] configured RBAC rules to allow certificate rotation for all node client certificates in the cluster
[bootstrap-token] Creating the "cluster-info" ConfigMap in the "kube-public" namespace
[kubelet-finalize] Updating "/etc/kubernetes/kubelet.conf" to point to a rotatable kubelet client certificate and key
[addons] Applied essential addon: CoreDNS
[addons] Applied essential addon: kube-proxyYour Kubernetes control-plane has initialized successfully!To start using your cluster, you need to run the following as a regular user:mkdir -p $HOME/.kubesudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/configsudo chown $(id -u):$(id -g) $HOME/.kube/configAlternatively, if you are the root user, you can run:export KUBECONFIG&#61;/etc/kubernetes/admin.confYou should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:https://kubernetes.io/docs/concepts/cluster-administration/addons/Then you can join any number of worker nodes by running the following on each as root:kubeadm join 172.21.24.197:6443 --token 33wev0.vwvmk139exv3ohx3 \--discovery-token-ca-cert-hash sha256:f25ef958e127c21168c661355c7df7280c71dc39ce277de9dabd3c1fb9cd9579

5、使用Flannel网络


这里需要使用到kube-flannel.yml文件&#xff0c;但由于墙的问题https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml 该网址下载不了&#xff1b;
可以使用 https://github.com/flannel-io/flannel/blob/master/Documentation/kube-flannel.yml下载或复制到服务器&#xff1b;


root&#64;host1:~# kubectl apply -f kube-flannel.yml
podsecuritypolicy.policy/psp.flannel.unprivileged created
clusterrole.rbac.authorization.k8s.io/flannel created
clusterrolebinding.rbac.authorization.k8s.io/flannel created
serviceaccount/flannel created
configmap/kube-flannel-cfg created
daemonset.apps/kube-flannel-ds created

6、主节点设置为调度节点&#xff08;多服务器可忽略&#xff09;


由于博主这里是单节点集群&#xff0c;所以需要将master节点也设置为调度节点


$ kubectl taint nodes --all node-role.kubernetes.io/master-

step3:Helm安装

$ curl -s https://get.helm.sh/helm-v3.5.2-linux-amd64.tar.gz | tar xzv
$ sudo cp linux-amd64/helm /usr/local/bin
$ rm -rf linux-amd64

添加使用 azure.cn 提供的 charts 镜像


$ helm repo add stable https://mirror.azure.cn/kubernetes/charts/
$ helm repo add incubator https://mirror.azure.cn/kubernetes/charts-incubator/# 更新本地 charts repo
$ helm repo update# 测试安装 redis chart
$ helm install my-redis stable/redis# 删除 redis
$ helm uninstall my-redis

到这里我们安装Jupyter的前置工作已经完成了&#xff0c;接下来就需要我们去安装Jupyter&#xff01;



step4:安装JupyterHub


现在我们已经有了Kubernetes集群&#xff0c;我们可以使用Helm通过 Helm chart安装JupyterHub和相关的Kubernetes资源。



1、相关配置

# 1、生成随机字符串作安全标识&#xff1a;
$ openssl rand -hex 32# 2、创建一个名为config.yaml的文件touch config.yaml# 3、使用命令vi config.yaml添加以下内容&#xff1a;
proxy:secretToken: ""其中<RANDOM_HEX>表示第一步中随机生成的字符串注意&#xff1a;secretToken: ""中冒号后有一个空格&#xff0c;缺少空格则后续操作无法进行。# 4、wq保存并退出

2、安装JupyterHub


helm添加软件仓库并更新仓库&#xff1a;


$ helm repo add jupyterhub https://jupyterhub.github.io/helm-chart/
$ helm repo update
# 安装完成
Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the "sqlfiddle" chart repository
...Successfully got an update from the "jupyterhub" chart repository
...Successfully got an update from the "emberstack" chart repository
Update Complete. ⎈ Happy Helming!

在config.yaml所在目录下执行下列命令安装chart&#xff1a;


RELEASE&#61;jhub
NAMESPACE&#61;jhubhelm upgrade --cleanup-on-fail \--install $RELEASE jupyterhub/jupyterhub \--namespace $NAMESPACE \--create-namespace \--version&#61;0.10.6 \--values config.yaml

⚠️在helm3中我们需要指定release&#xff0c;如果没有就使用 --generat-name&#61;



在执行步骤2的过程中&#xff0c;您可以通过输入其他终端来查看正在创建的Pod&#xff1a;


root&#64;host1:~# kubectl get pod --namespace jhub
NAME READY STATUS RESTARTS AGE
continuous-image-puller-mp7mq 1/1 Running 0 25s
hub-55dcd585c-6dpwr 0/1 ContainerCreating 0 25s
proxy-7645dd5d94-fvgsm 1/1 Running 0 25s
user-scheduler-7db7bfbdc6-k76xj 0/1 ErrImagePull 0 25s
user-scheduler-7db7bfbdc6-qg64l 0/1 ContainerCreating 0 25s

等待hub和proxy都进入running状态


root&#64;host1:~# kubectl get pod --namespace jhub
NAME READY STATUS RESTARTS AGE
continuous-image-puller-mp7mq 1/1 Running 0 2m22s
hub-55dcd585c-6dpwr 1/1 Running 0 2m22s
proxy-7645dd5d94-fvgsm 1/1 Running 0 2m22s

使用 kubectl get service --namespace jhub命令找到proxy-public对应的端口号


root&#64;host1:~# kubectl get service --namespace jhub
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
hub ClusterIP 10.105.101.125 <none> 8081/TCP 14h
proxy-api ClusterIP 10.100.241.193 <none> 8001/TCP 14h
proxy-public NodePort 10.101.104.188 <none> 80:31420/TCP 14h

打开浏览器&#xff0c;地址栏输入主机ip:端口号访问并使用jupyterhub。

⚠️这里如果有朋友使用的是服务器&#xff0c;一定要将服务器的安全组修改&#xff0c;入方向的端口和IP修改一下&#xff01;&#xff01;&#xff01;切记


在这里插入图片描述


3、⚠️问题


1、proxy-public如果处于pending状态&#xff0c;是因为svc暴露给外网的方式为LoadBalancer&#xff0c;又没有配转发&#xff0c;所以获取不到ip&#xff1b;修改svc中的type为NodePort&#xff0c;通过使用本机ip&#43;端口的方式暴露给外网。使用如下命令&#xff1a;


kubectl -n jhub get svc
kubectl -n jhub edit svc proxy-public
# 找到type字段将LoadBalancer修改为NodePort

2、hub的pod处于pending状态&#xff0c;kubectl describe pod &#43; pod名&#xff0c;如果报错“pod has unbound immediate PersistentVolumeClaims”&#xff0c;则修改helm安装jupyterhub时的config.yaml文件&#xff0c;添加以下内容&#xff1a;&#xff08;这个问题困扰了我很久&#xff0c;感谢博友的解答&#xff09;


hub:db:type: sqlite-memory
singleuser:storage:type: none

然后重新执行以下命令&#xff1a;


RELEASE&#61;jhub
NAMESPACE&#61;jhubhelm upgrade --cleanup-on-fail \--install $RELEASE jupyterhub/jupyterhub \--namespace $NAMESPACE \--create-namespace \--version&#61;0.10.6 \--values config.yaml

总结


在整个安装过程中遇到了各类bug&#xff0c;好在博友们都很强大&#xff0c;在github和博客上有很多解决方案&#xff0c;大家可以去参考&#xff01;
在这里记录一下对我有重要帮助的博友链接&#xff1a;
https://github.com/maguowei/gotok8s
https://zero-to-jupyterhub.readthedocs.io/en/stable/jupyterhub/installation.html
https://blog.csdn.net/u012174752/article/details/89173916
https://www.jianshu.com/p/491a562127fa



欢迎大家一起关注交流学习哈&#xff01;
个人GitHub&#xff1a;https://github.com/SpecialAll



推荐阅读
  • 现在比较流行使用静态网站生成器来搭建网站,博客产品着陆页微信转发页面等。但每次都需要对服务器进行配置,也是一个重复但繁琐的工作。使用DockerWeb,只需5分钟就能搭建一个基于D ... [详细]
  • python中安装并使用redis相关的知识
    本文介绍了在python中安装并使用redis的相关知识,包括redis的数据缓存系统和支持的数据类型,以及在pycharm中安装redis模块和常用的字符串操作。 ... [详细]
  • 本文介绍了在Ubuntu 11.10 x64环境下安装Android开发环境的步骤,并提供了解决常见问题的方法。其中包括安装Eclipse的ADT插件、解决缺少GEF插件的问题以及解决无法找到'userdata.img'文件的问题。此外,还提供了相关插件和系统镜像的下载链接。 ... [详细]
  • 本文介绍了利用ARMA模型对平稳非白噪声序列进行建模的步骤及代码实现。首先对观察值序列进行样本自相关系数和样本偏自相关系数的计算,然后根据这些系数的性质选择适当的ARMA模型进行拟合,并估计模型中的位置参数。接着进行模型的有效性检验,如果不通过则重新选择模型再拟合,如果通过则进行模型优化。最后利用拟合模型预测序列的未来走势。文章还介绍了绘制时序图、平稳性检验、白噪声检验、确定ARMA阶数和预测未来走势的代码实现。 ... [详细]
  • 如何自行分析定位SAP BSP错误
    The“BSPtag”Imentionedintheblogtitlemeansforexamplethetagchtmlb:configCelleratorbelowwhichi ... [详细]
  • 本文介绍了Redis的基础数据结构string的应用场景,并以面试的形式进行问答讲解,帮助读者更好地理解和应用Redis。同时,描述了一位面试者的心理状态和面试官的行为。 ... [详细]
  • eclipse学习(第三章:ssh中的Hibernate)——11.Hibernate的缓存(2级缓存,get和load)
    本文介绍了eclipse学习中的第三章内容,主要讲解了ssh中的Hibernate的缓存,包括2级缓存和get方法、load方法的区别。文章还涉及了项目实践和相关知识点的讲解。 ... [详细]
  • 本文介绍了在CentOS上安装Python2.7.2的详细步骤,包括下载、解压、编译和安装等操作。同时提供了一些注意事项,以及测试安装是否成功的方法。 ... [详细]
  • 本文介绍了MVP架构模式及其在国庆技术博客中的应用。MVP架构模式是一种演变自MVC架构的新模式,其中View和Model之间的通信通过Presenter进行。相比MVC架构,MVP架构将交互逻辑放在Presenter内部,而View直接从Model中读取数据而不是通过Controller。本文还探讨了MVP架构在国庆技术博客中的具体应用。 ... [详细]
  • 本文介绍了在Ubuntu下制作deb安装包及离线安装包的方法,通过备份/var/cache/apt/archives文件夹中的安装包,并建立包列表及依赖信息文件,添加本地源,更新源列表,可以在没有网络的情况下更新系统。同时提供了命令示例和资源下载链接。 ... [详细]
  • 本文概述了JNI的原理以及常用方法。JNI提供了一种Java字节码调用C/C++的解决方案,但引用类型不能直接在Native层使用,需要进行类型转化。多维数组(包括二维数组)都是引用类型,需要使用jobjectArray类型来存取其值。此外,由于Java支持函数重载,根据函数名无法找到对应的JNI函数,因此介绍了JNI函数签名信息的解决方案。 ... [详细]
  • 本文介绍了在Ubuntu系统中清理残余配置文件和无用内容的方法,包括清理残余配置文件、清理下载缓存包、清理不再需要的包、清理无用的语言文件和清理无用的翻译内容。通过这些清理操作可以节省硬盘空间,提高系统的运行效率。 ... [详细]
  • tcpdump 4.5.1 crash 深入分析
    tcpdump 4.5.1 crash 深入分析 ... [详细]
  • 如何使用PLEX播放组播、抓取信号源以及设置路由器
    本文介绍了如何使用PLEX播放组播、抓取信号源以及设置路由器。通过使用xTeve软件和M3U源,用户可以在PLEX上实现直播功能,并且可以自动匹配EPG信息和定时录制节目。同时,本文还提供了从华为itv盒子提取组播地址的方法以及如何在ASUS固件路由器上设置IPTV。在使用PLEX之前,建议先使用VLC测试是否可以正常播放UDPXY转发的iptv流。最后,本文还介绍了docker版xTeve的设置方法。 ... [详细]
  •  项目地址https:github.comffmydreamWiCar界面做的很难看,美工方面实在不在行。重点是按钮触摸事件的处理,这里搬了RepeatListener项目代码,例 ... [详细]
author-avatar
一片绿洲053766
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有