ECS 打造云端开发/协同办公 “军火库”

本文涉及的产品
云原生数据库 PolarDB MySQL 版,Serverless 5000PCU 100GB
云服务器 ECS,每月免费额度200元 3个月
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
简介: 本文着重在 ECS 的使用实践,面向个人开发者或者是小型团队。借着这次评测的机会,期望把一些个人实践分享出来供大家交流,全文篇幅较长,涉及到的面也会广一些,如果你正计划学习 Kubernetes ,我期望本文对你入门 Kubernetes 生态会有一定的实践帮助,让我们看一下新一代性能怪兽 ECS 可以激起多大的浪花🌊。

前言

本文着重在 ECS 的使用实践,面向个人开发者或者是小型团队。借着这次评测的机会,期望把一些个人实践分享出来供大家交流,全文篇幅较长,涉及到的面也会广一些,如果你正计划学习 Kubernetes ,我期望本文对你入门 Kubernetes 生态会有一定的实践帮助,让我们看一下新一代性能怪兽 ECS 可以激起多大的浪花🌊 。


这里我画了一下本文的结构图,结构相对比较清晰,我们将基于 ECS 进行扩展,包括存储计算分离、应用容器级别的高弹性、基于 Terraform 的云资源操作等,并结合现有成熟的 SaaS 服务。基于 ECS 构建出一整套高弹性、可水平扩展、多方位监控等特性的集群。

image.png


由于社区右侧目录只能支持到三级, 三四级目录会造成同级显示,在此处我会对文章整体的结构进行一个概括,方便您有一个大概的了解:

  • Part1: 对 ECS 选型以及性能测试
  • Part2: 准备阶段,会基于单台的 ECS 进行一些初始化配置讲解
  • Part3: 部署 K3s 底座,其中包括存储(自建/NAS)以及负载组件以及常用中间件的部署
  • Part4: 实践场景,包括结合云效构建个人博客,构建个人云端 IDE,团队协作办公组件部署等场景
  • Part5: 计算节点的添加,包括手动部署、通过 terraform 操作、ECS 结合 ECI 等场景
  • Part6: 全方位监控告警,包括应用、机器监控等
  • Part7: 总结


服务器选型/测试

选型

这里我们选用的是测评给到的机器 c5 服务器,2c4G,公网带宽 1M,操作系统的话按照习惯重新安装的 Ubuntu 20.04。

image.png

挑选 vps 需要考虑到地域,网络规划等等方面,没有比官方文档更合适的了,大家可以参考选型的最佳实践

  • 根据个人的经验,如果考虑到作为开发者个人的云端工具库,可以选 计算型 C5 2c4G  规格长期使用,可以应付大部分的场景。
  • 如果是有一些临时需要测试的场景需要大量的机器(比如作为中转机,测试弹性以及大数据的场景),我一般选择 按量付费  -》 C7 计算型 2c4G/4c8G的规格,可以随用随释放,基本可以满足个人的测试场景,并且费用不会很高。或者是结合 ECI 进行使用(后续有测试案例)。

image.png


性能测试

我们通过 bench.sh 来进行简单的 io 以及 网络测试

  • 平均 io 在 106MB/s 这个只是一个简单的参考标准
  • 在国内下载速度以及延迟维持在一个很低的值
wget-qO- bench.sh | bash

image.png

如果需要更加详细的基准测试指标,可以使用 byte-unixbench, byte-unixbench 提供了更加详细的指标,直接使用镜像运行测试非常方便。

由于 byte-unixbench 是一个基准,测试结果会受到硬件操作系统等等的影响(可以参考 README),感兴趣的小伙伴可以按需测试。


可以从实例管理中看到,ECS 挂载的是高效磁盘,IOPS 给出的标准是 1960

image.png

我们通过 fio 对磁盘进行一下测试,编写 fio 配置文件,我们分别对 随机读,随机写,顺序写 进行测试

cat<<EOF>config.fio[global]filename=/dev/vdaioengine=libaiodirect=1bs=4kiodepth=16runtime=60threadgroup_reporting[randread]rw=randreadnumjobs=5stonewall[randwrite]rw=randwritesize=1Gnumjobs=5stonewall[write]rw=writesize=1Gnumjobs=5stonewallEOF

执行等待测试完成,由于报告过长,这里只展示部分信息,具体的测试配置大家可以参考官方文档。

fio config.fio

可以看到在三组测试中,IOPS 都与云盘规格相同。

fio-3.16
Starting 15 threads
Jobs: 5(f=5): [_(10),W(5)][27.7%][w=11.1MiB/s][w=2852 IOPS][eta 07m:50s]                      
randread: (groupid=0, jobs=5): err=0: pid=2358774: Mon Apr 1821:55:36 2022  read: IOPS=1975, BW=7901KiB/s (8091kB/s)(463MiB/60048msec)
  ...
randwrite: (groupid=1, jobs=5): err=0: pid=2360284: Mon Apr 1821:55:36 2022write: IOPS=1971, BW=7885KiB/s (8074kB/s)(463MiB/60083msec); 0 zone resets
  ...
write: (groupid=2, jobs=5): err=0: pid=2361794: Mon Apr 1821:55:36 2022write: IOPS=2546, BW=9.95MiB/s (10.4MB/s)(597MiB/60032msec); 0 zone resets
  ...
Run status group 0 (all jobs):
   READ: bw=7901KiB/s (8091kB/s), 7901KiB/s-7901KiB/s (8091kB/s-8091kB/s), io=463MiB (486MB), run=60048-60048msecRun status group 1 (all jobs):
  WRITE: bw=7885KiB/s (8074kB/s), 7885KiB/s-7885KiB/s (8074kB/s-8074kB/s), io=463MiB (485MB), run=60083-60083msecRun status group 2 (all jobs):
  WRITE: bw=9.95MiB/s (10.4MB/s), 9.95MiB/s-9.95MiB/s (10.4MB/s-10.4MB/s), io=597MiB (626MB), run=60032-60032msecDisk stats (read/write):
  vda: ios=118714/272163, merge=0/610, ticks=4795956/9664295, in_queue=13892048, util=97.79%


准备阶段

初始化

首先我们登陆到服务器,修改 ssh 配置 禁止使用密码登陆, 将本地公钥添加到 authorized_keys。

ssh key 可以通过 ssh-keygen 生成,默认都会生成到 用户目录的 .ssh 下。

vim /etc/ssh/sshd_config   # 修改内容见下图service sshd restartecho"ssh-rsa 替换成本地的公钥" >>  ~/.ssh/authorized_keys 

image.png

使用密钥登陆可以优雅的避免被暴力破解,同样不用担心本地的 ssh 密钥被重置掉,ecs 提供了 vnc 链接的方式让我们可以直接操作。

image.png


更改服务器 hostname,这里我按照 node-内网IP  的规则命名。

hostnamectl set-hostname node-172019221084

安全组放行端口,我们计划使用 ingress 作为流量入口,所以放行 80/443 即可,详细操作可以参考 添加安全组规则

image.png


部署 k3s 底座

为什么是 k3s?

需要回答这个问题,首先要说一下为什么容器化?最主要的一点容器化保证了服务运行环境的一致性,正因为这一点,大大推动了 devops 的发展,让跨环境、灰度发布等都十分轻松,使用容器让我们在 ECS 上更加的快捷方便。


其次再来回答为什么是 kubernetes,对于个人开发者/中小型企业来说,每年都会有云厂商的福利,低价买到一些云服务器。使用kubernetes 可以轻松的将新服务器作为计算节点加入到我们的个人集群,跨云厂商也毫无压力。再加上云厂商的 SaaS 服务有很多的免费额度,比如云效的流水线,阿里云的容器镜像仓库等,足够我们开发者或者是小型的团队使用,服务器仅用于发布应用或者跑一些中间件即可。


而 k3s 作为 kubernetes 轻量发行版,占用资源极少,对于不太充足的服务器资源是很好的选择。当然如果资源充足的情况下,强烈建议在 ECS 部署高可用 kubernetes 或者是上 ACK

image.png


部署 k3s

安装 wireguard

apt-get update
apt install -y wireguard

执行如下命令安装,参数解释:

参数

解释

K3S_EXTERNAL_IP

ECS 的公网ip, 可以在实例详情中查看

INSTALL_K3S_MIRROR

cn,指定使用国内源

INSTALL_K3S_EXEC

--tls-san: 证书的 san,根据是否需要公网访问 apiserver 来按需选择

--flannel-backend:使用 wireguard 作为后端,方便我们打通其他服务器,具体请参考

--kube-proxy-arg:kubeproxy 配置,我们选用 ipvs 模式

--disable:k3s 默认会安装 traefik 作为 ingress controller,这里我选择自己安装 nginx ingress controller


exportK3S_EXTERNAL_IP="you external ip"exportINSTALL_K3S_MIRROR=cn
exportINSTALL_K3S_EXEC="--write-kubeconfig ~/.kube/config --write-kubeconfig-mode 666 --tls-san $K3S_EXTERNAL_IP--node-external-ip $K3S_EXTERNAL_IP--flannel-backend wireguard--kube-proxy-arg proxy-mode=ipvs masquerade-all=true metrics-bind-address=0.0.0.0--disable traefik,servicelb"curl-sfL http://rancher-mirror.cnrancher.com/k3s/k3s-install.sh | sh-

执行安装后,我们可以通过 kubectl 来查看节点状态

image.png


(可选) 如果有卸载或者重装的需求,可以直接执行

k3s-uninstall.sh  


安装 helm

helm 作为 kubernetes 生态的应用管理工具,大部分的开源项目都有提供 chart 包,可以方便的进行应用管理,可以算得上是 kubernetes 应用管理的 “瑞士军刀”。


通过如下命令安装 helm3

wget https://get.helm.sh/helm-v3.8.1-linux-amd64.tar.gz
tar -zxvf helm-v3.8.1-linux-amd64.tar.gz
mv linux-amd64/helm /usr/local/bin && chmod+x /usr/local/bin/helm


部署存储

考虑到我们后续会有其他的节点加入进来,为了让我们的计算跟存储可以分离,方便后续计算节点的扩充,服务可以“漂起来”,我们需要部署 CSI 插件,这里推荐如下几种:

  • 如果手里有 NAS/云盘 等资源,强烈建议作为存储,可以做到计算与存储的分离,只需要部署 alibaba-cloud-csi-driver ,对接 NAS/云盘 即可(OSS 不支持通过 StorageClass 动态管理 pvc)。
  • 使用 NFS,我们需要自己手动搭建一个 nfs-server,然后使用 nfs-subdir-external-provisioner 对接即可。
  • 使用 GlusterFS,基于 glusterfskadalu 来作为分布式存储解决方案,kadalu 可以让我们无需关心 glusterfs 安装,而且非常轻量。
  • 其他方案:openbs, longhorn,rook,ceph 等等


上述方案大部分都会通过 StorageClass 来管理 pvc,后续部署只需要声明使用的 sc 即可,我们这里选择前三种来实操下。


nas

nas 可以按使用量付费,存储价格也很便宜,如果没有特殊要求,非常建议搭配 ECS 使用。

首先我们部署 csi-driver,等待组件启动完成

git clone https://github.com/kubernetes-sigs/alibaba-cloud-csi-driver.git && cd alibaba-cloud-csi-driver
kubectl apply -f deploy/rbac.yaml 
kubectl apply -f ./deploy/nas

image.png

购买 NAS,这里我们选择容量型,地区与 ECS 一致,其他的按需配置

image.png

进入到 NAS 管理页面,我们根据 ECS 所在的专有网络以及交换机,配置挂载点

image.png

挂载点配置完成后,我们回到 ECS 编写 StorageClass 配置

  • 其中 server 配置就是上图中我们的挂载点,我们采用 subpath 的方式
  • 后面的 /data 就是我们指定的目录,所有 pv 的目录都在该文件夹下
cat <<EOF > alicloud-nas-sp-sc.yaml 
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: alicloud-nas-sp
mountOptions:
- nolock,tcp,noresvport
-vers=3parameters:
  volumeAs: subpath
  server: "your_mountpoint_address:/data"  archiveOnDelete: "false"provisioner: nasplugin.csi.alibabacloud.com
reclaimPolicy: Delete
EOF

创建 sc

kubectl apply -f alicloud-nas-sp-sc.yaml 

image.png

此时我们使用项目中自带的 demo 做一下测试,可以看到 nas 成功绑定,具体存储的 path 如下所示

kubectl apply -f ./examples/nas/dynamic/pvc-subpath.yaml

image.png


kadalu

执行如下命令进行安装

curl-fsSL https://github.com/kadalu/kadalu/releases/latest/download/install.sh | sudobash-xkubectl kadalu install

等待组件安装完成

image.png

这时候我们创建个 data 目录,并且作为集群的存储。考虑到是个人开发环境,这里我们一个节点存储数据即可,如果要求稳定至少请至少上三节点或者使用 NAS。

mkdir-p /data/storage-pool-1
kubectl kadalu storage-add storage-pool-1 --path node-172019221084:/data/storage-pool-1 

image.png

这时候查看我们的 storage class 已经创建出来了。后续可以直接使用该 sc

kubectl get sc 

image.png到这里我们的 glusterfs 存储就部署完成了


nfs

首先我们部署 nfs-server

apt-get install nfs-kernel-server -y# (可选)如果非 nfs server 节点,其他的 ECS 节点都需要安装 nfs clientapt install nfs-common -y

创建存储目录,并配置访问权限

mkdir /data/nfs
chmod go+w /data/nfs
echo"/data/nfs *(rw,sync)" >> /etc/exports
systemctl restart nfs-server

如果有其他的 ECS 节点需要访问 nfs,这里我们在安全组中限制只有节点之间可以访问 nfs-server 的端口, 或者推荐直接限制来源,放行给其他节点所有端口。


添加 repo 仓库

helm repo add nfs-subdir-external-provisioner https://kubernetes-sigs.github.io/nfs-subdir-external-provisioner/
helm repo update

编写 values.yaml, 指定 nfs-server 的端口以及路径

cat <<EOF > nfs-csi-values.yaml
image:
  repository: registry.cn-shanghai.aliyuncs.com/viper/nfs-subdir-external-provisioner
nfs:
  server: your_ecs_ip
  path: /data/nfs
EOF

执行安装即可

helm upgrade --install nfs-subdir-external-provisioner nfs-subdir-external-provisioner/nfs-subdir-external-provisioner -f nfs-csi-values.yaml -n nfs-provisioner-system --create-namespace

安装完成后,可以看到对应的 StorageClass 已经存在,后续使用即可

image.png



部署 ingress controller

k3s 以及 存储我们已经部署完成,接下来我们部署 ingress controller 来作为我们整个集群的流量入口,这里选择的是通过 helm 安装 nginx ingress controller。


添加 ingress-nginx 的 repo

helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update

编写我们的 values 文件,我们采用 Daemonset 方式部署,由于我这边没有备案的域名,我们选择流量入口为 1080 以及 1443

cat <<EOF > ingress-nginx-values.yaml
controller:
  image:
    registry: registry.cn-shanghai.aliyuncs.com/viper
    image: ingress-nginx-controller
    digest: sha256:bc30cb296e7548162afd9601f6b96261dcca8263e05b962694d1686b4d5a9584
  extraArgs:
    https-port: 1443    http-port: 1080  watchIngressWithoutClass: true  hostNetwork: true  kind: DaemonSet
  nodeSelector:
    ingress: "true"  admissionWebhooks:
    patch:
      image: 
        registry: registry.cn-shanghai.aliyuncs.com/viper
        image: kube-webhook-certgen
        digest: sha256:78351fc9d9b5f835e0809921c029208faeb7fbb6dc2d3b0d1db0a6584195cfed
EOF

我们将当前 ECS 的节点打上 ingress 标签,作为集群流量入口

kubectl label no node-172019221084 ingress=true

部署 ingress-controller,等待部署完成。

helm install ingress-nginx ingress-nginx/ingress-nginx --version=4.0.8 -f ingress-nginx-values.yaml -n ingress-nginx --create-namespace

部署完成后,如果访问需要 https,我们需要利用 acme.sh 来配合 阿里云 dns 实现泛域名证书的自动续期,这里就不做赘述了,官方文档写得非常详细,可以创建 ak/sk 利用 dns_ali 实现对泛域名的自动续期。

这里有个需要注意的地方是,我们需要结合 acme.sh 生成的证书来更新到 secret 中,可以在定时任务中增加如下部分,将 secret 更新。

kubectl delete secret ingress-tls -n ingress-nginx
kubectl create secret generic ingress-tls --from-file=tls.crt=generic-cert.pem --from-file=tls.key=generic-key.pem -n ingress-nginx

(可选)在 ingress 的 values.yaml 中声明 secret 名称,如下配置所示。

controller:  extraArgs:    default-ssl-certificate: "ingress-nginx/ingress-tls"


部署常见中间件

我们可以部署一些常见的中间件,比如 MySQL(建议购买 rds,活动的时候真的太香了),Redis,ETCD 等,这里我们部署一个开发用的 mysql。


添加 repo

helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update

部署 mysql,这里我们 storage class 使用我们上面部署的存储

helm install mysql bitnami/mysql -n addons-system --create-namespace--set global.storageClass="kadalu.storage-pool-1"

部署完成后,可以根据提示查看默认 root 密码

image.png


此时我们可以查看下监控数据,不得不说 ECS 真的太强了

image.png


实践场景

场景1: 部署博客

这里我们结合云效与阿里云镜像仓库来部署我们的个人博客,实例代码请参考 hugo-quickstart,案例中我们对博客这个应用添加了 ingress,并设定了域名。

image.png


首先我们创建一条流水线,选择部署到 Kubernetes,其中集群链接我们可以登陆在 ECS 中执行如下命令查看,其中的 server 地址换成我们的公网入口

cat ~/.kube/config

image.png

image.png

执行流水线,构建并上传镜像到阿里云镜像仓库,通过我们代码仓库中的 manifests/manifests.yaml 部署到我们的 ECS。

image.png

此时可以登录到集群中查看是否部署成功

kubectl get po -n blog-system

image.png


我们此时根据配置的域名进行一下做一下域名解析并访问,比如 blog.xxxx:1080, 可以看到我们的博客已经部署成功了。

截屏2022-03-31 23.49.00.png

我们可以在云效中提供的 webhook 配置到 github 的 workflow 中,通过提交代码自动触发流水线构建发布到 ECS,这里就不做演示了,之后计划专门有一篇文章介绍 github workflow。


场景2: 打造个人云端开发环境

开源产品 code-server,可以直接在浏览器中使用,我们来将 code-server 部署到我们的 ECS 中。


首先克隆 coder-server 代码

git clone https://github.com/coder/code-server

编写配置文件,这里我们指定域名以及存储(使用之前部署的 kadalu 或者其他 csi)

cat <<EOF > coder-values.yaml
ingress:
  enabled: true  hosts:
- host: "coder.your.domain"    paths:
- /
persistence:
  storageClass: kadalu.storage-pool-1
  size: 1G
EOF


安装,等待 coder namespace 下所有组件起来

helm install coder code-server/ci/helm-chart -f coder-values.yaml --namespace coder --create-namespace

根据提示我们获取初始密码

image.png


此时我们访问配置的域名,输入上述密码

image.png

熟悉的 vscode 展现在我们面前了,coder 也是目前大多数厂商在线 IDE 的基石,此时我们可以登录 github 账号同步并且安装一些常见的插件,比如 数据库管理,Kubernetes支持,nocalhost 等。

除了开发过程在 coder 以外,可以将代码、个人知识库、CI/CD 全部托管到云效上,完美的利用好现有的 SaaS 资源,才是真的做到应用生在云上,长在云上。

image.png


场景3: 私有化云上办公

在该场景中,我们将基于 nextcloud + onlyoffice 组合,实现云上办公套件,可以实现私有化云盘、office系统处理等等。需要注意的是如果该场景需要添加节点,大家可以参考本文下一章节 计算节点添加  部分,扩充节点,话不多说我们现在开始。


部署 nextcloud

首先我们部署 nextcloud,nextcloud 的 chart 包在本人写时还是存在一些问题的,比如使用 local 以外的 provisoner 存在问题:issue。所以我们还是按照 helm 使用流程,添加 repo 编写 values.yaml。

helm repo add nextcloud https://nextcloud.github.io/helm/
helm repo update

参数解释:

  • ingress:开启 ingress 访问,我们nextcloud对外暴露,后面部署的 onlyoffice作为集群内服务。
  • affinity:由于使用 local 存储,我们利用亲和性选择 app/nextcloud=true 的节点。
  • internalDatabase:我们这里不使用默认的 sqlite,使用外部 mysql,需要禁用,否则即使启用外部数据库,仍然会用 sqlite。当然你也可以直接使用默认的 sqlite。
  • nextcloud:配置 ingress 域名,默认管理员信息,php 配置等
  • externalDatabase:这里我们使用上面部署的 mysql,提前创建好数据库。目前虽然官方支持 postgresql,不过在写该文章时候社区关于 external 链接 pg 的 issue 仍然没有关闭。
  • 健康检查设置的失败次数多点,依赖外部数据库初始化时间较长。
  • persistence:存储,这里我们 enable,由于是 k3s 这里的 local 的 storageClass 不用写,默认就是 local-path 
  • 其他比如邮箱服务等等,可以按需配置
cat <<EOF > nextcloud-values.yaml
ingress:
  enabled: trueaffinity:
  nodeAffinity:
    requiredDuringSchedulingIgnoredDuringExecution:
      nodeSelectorTerms:
- matchExpressions:
- key: app/nextcloud
          operator: Exists
internalDatabase:
  enabled: falsenextcloud:
  host: your.domian
  username: your_custom_username
  password: your_custom_password
  configs:
    custom.config.php: |-
      <?php
$CONFIG= array (
'allow_local_remote_servers'=> 'true',
        );
externalDatabase:
  enabled: true  type: mysql
  host: mysql.addon-system.svc.cluster.local
  database: nextcloud
  user: xxxxxx
  password: xxxxxx
livenessProbe:
  failureThreshold: 600readinessProbe:
  failureThreshold: 600persistence:
  enabled: trueEOF

部署并选择一个节点打标

kubectl label no node-172019221084 app/nextcloud=truehelm upgrade --install nextcloud nextcloud/nextcloud -n office-system -f nextcloud-values.yaml

等待初始化完成即可,我们 dns 解析上述配置的域名,并且通过预设的账号密码登录。

image.png

登录过后我们进入到精选应用中下载安装并启用 OnlyOffice,用于后续与 documentserver 集成。

image.png

部署 documentserver

kubernetes 上部署 onlyoffice,是较为新的一个项目,这里我们先来按照该项目来尝尝鲜。大家同样的可以按需选择官方 docker 镜像直接编写 yaml 部署。

documentserver 依赖 rabbitmq,redis,postgresql,我们先来部署中间件,同样的放到 office-system 下。


添加 repo

helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update


部署 rabbitmq

  • rabbitmq 我们只需要指定 sc 即可,大家可以根据上面部署存储章节选择自己的 sc。
cat <<EOF > rabbitmq-values.yaml
persistence:
  storageClass: kadalu.storage-pool-1
EOF
helm upgrade --install rabbitmq bitnami/rabbitmq -n office-system --create-namespace-f rabbitmq-values.yaml

部署 redis

  • 这里 redis 我们跳过认证
cat <<EOF > redis-values.yaml
global:
  storageClass: kadalu.storage-pool-1
architecture: standalone
image:
  tag: 5.0.7-debian-10-r51
auth:
  enabled: falseEOF
helm upgrade --install redis bitnami/redis -n office-system --create-namespace-f redis-values.yaml

获取 documentserver 初始化 sql 并创建为 configmap

wget-O createdb.sql https://raw.githubusercontent.com/ONLYOFFICE/server/master/schema/postgresql/createdb.sql
kubectl create configmap -n office-system init-db-scripts --from-file=./createdb.sql

部署 postgresql

  • 声明默认初始化 sql
cat <<EOF > postgresql-values.yaml
global:
  storageClass: kadalu.storage-pool-1
primary:
  initdb:
    scriptsConfigMap: init-db-scripts
  persistence:
    size: 8Gi
auth:
  database: postgres
EOF
helm install postgresql bitnami/postgresql -n office-system --create-namespace-f postgresql-values.yaml

这时候依赖的中间件就部署完成了,我们开始部署主角

  • documentserver 默认 chart 就是按照 bitnami 一些参数作为默认值的,所以我们只需要 sc 即可
git clone https://github.com/ONLYOFFICE/Kubernetes-Docs.git
cat <<EOF > documentserver-values.yaml
persistence:
  storageClass: kadalu.storage-pool-1
EOF
helm install document-server ./Kubernetes-Docs/ -n office-system -f documentserver-values.yaml

这里我们等待所有组件起来即可进行解下来的配置

image.png


nextcloud 集成 docuementserver

此时我们来到 nextcloud 来通过之前安装的 connector 集成 documentserver,在 设置中找到 ONLYOFFICE,配置 documentserver 的地址,由于我们两个组件都在同一个 namespace 下,可以直接通过 service 名称访问到

  • 其中的秘钥可以查看 jwt secret
kubectl get secret -n office-system jwt -ojsonpath="{.data.JWT_SECRET}" | base64 -d
  • 这里我修改了一下用于 ONLYOFFICE DCOS 内部请求的服务器地址,默认的协议与端口不匹配。

配置完成后,如果校验成功会出现 onlyoffice 的个性化配置。

image.png


配置保存完成后,我们创建一个 excel,并且分享到其他用户,可以看到在线实时协同处理文档。一个基于 ECS 的轻量化办公协同杀手锏就完成了!

image.png


计算节点添加

上述几个部分介绍了 ECS 作为 k3s 中心节点的一些场景,接下来的部分我们将介绍一下 ECS 作为计算节点的添加,将从如下几个部分去介绍:

  1. ECS 直接部署 k3s-agent 接入到中心承载计算能力。
  2. 通过 Terraform 批量操作 ECS 资源,自动接入中心承载计算能力。
  3. 使用 ECI 作为计算节点,低成本超高弹性的云上计算能力。


ECS 部署 k3s-agent

我们重置该服务器(这里我选择的仍是 ubuntu 20.04)作为计算节点添加到其他的中心节点下。


首先还是需要重命名节点,这里按照我这边集群的命名风格

hostnamectl set-hostname node-alibaba-2

同样的我们安装 wireguard

apt-get update
apt install -y wireguard


安装完成 wireguard 后,我们登录到中心节点,通过如下命令获取 agent 加入集群的 Token 凭证

cat /var/lib/rancher/k3s/server/node-token


接下来我们配置 k3s agent 的安装参数

参数

解释

K3S_TOKEN

凭证,上个步骤获取的值

K3S_URL

k3s apiserver 的公网地址,一般是中心节点公网地址的 6443 端口

INSTALL_K3S_MIRROR

与中心参数解释一致

K3S_EXTERNAL_IP

与中心参数解释一致

INSTALL_K3S_VERSION

k3s 安装版本,这里选择与中心一致的版本

INSTALL_K3S_EXEC

基本与中心部署参数一致,多了认证相关的,少了控制节点的参数


安装完成后,查看 k3s-agent 服务状态是否正常

service k3s-agent status


接下来到中心节点,查看集群的状态,可以看到 node-alibaba-2 节点已经加入到集群中了

kubectl get no 

image.png

这里其实是有一个小坑的,flannel 在 k3s 集群公网之间的访问存在问题,可以参考 flannel-fixer 这个项目,部署到中心集群,会自动帮我们解决掉这个问题,原理也比较简单,通过 list/watch 节点资源,添加 flannel 的 annotation 到节点上,感兴趣的可以研究下。

image.png


(可选)如果有 agent 卸载重装的需求,可以执行如下命令

k3s-agent-uninstall.sh

通过 Terraform 批量添加

上一部分介绍的是如何在一台干净的 ECS 上去拉起我们的计算节点,操作方式过于“原始”了,对于 iaas 层资源的操作其实有更优雅的方式进行创建以及批量销毁,那就是 IaC (Infrastructure as Code)

Terraform 目前算是 IaC 最常用的工具了,阿里云基本常见的资源都在 provider 中有提供,使用 terraform 在运维成本上会更加的有效,如果你没有接触过,希望本部分带你入门阿里云产品操作的新姿势。


安装并配置 terraform

可以通过链接访问并下载 terraform 的 cli,只需要一个二进制即可,这里我使用 brew 安装

brew install terraform


安装完成后我们需要三个环境变量,一套 AKSK,还有我们云产品所在的区域,这对于 alicloud provider 是必须的。

exportALICLOUD_ACCESS_KEY=xxxx
exportALICLOUD_SECRET_KEY=xxxx
exportALICLOUD_REGION="cn-wulanchabu"

我们来到 AKSK 管理,授权给子账号 ECS 以及 VPC 的所有权限

由于我测试是在 cn-wulanchabu, 区域下没有 VPC,如果你已经在 Region 下有了 VPC 相关的配置,根据执行权限最小化的原则,只需要给只读权限就好。


编写资源描述

terraform 语法相对来说比较简单清晰,我们主要参考阿里云的 provider 文档来对资源的字段以及上下文传递操作。


我们先创建一个项目目录,用来存储 k3s-agent-install 相关的 terrform 配置。

首先创建一个文件 variables.tf 用来存储我们一些需要变动的变量,其中我们标识了镜像、区域、ecs 购买的类型、购买的数量等。


variable "instance_count" {
  default =2}
variable "image_id" {
  default ="ubuntu_20_04_x64_20G_alibase_20220331.vhd"}
variable "zone" {
  default ="cn-wulanchabu-c"}
variable "ecs_type" {
  default ="ecs.t6-c2m1.large"}

接下来我们创建 terraform.tf,来描述我们资源以及操作。

我们先来创建 vpc 相关的配置,这里创建 vpc,vswitch,安全组,安全组规则。

TIPS:  如果该区域内已经有通用配置好的 vpc 以及安全组等,直接跳过即可

provider "alicloud" {}
resource "alicloud_vpc""vpc" {
  vpc_name   ="tf_ecs_k3s_vpc"  cidr_block ="172.16.0.0/12"}
resource "alicloud_vswitch""vsw" {
  vpc_id            = alicloud_vpc.vpc.id
  cidr_block        ="172.16.0.0/21"  zone_id           = var.zone
}
resource "alicloud_security_group""default" {
  name ="default"  vpc_id = alicloud_vpc.vpc.id
}
resource "alicloud_security_group_rule""allow_all_tcp" {
  type              ="ingress"  ip_protocol       ="tcp"  nic_type          ="intranet"  policy            ="accept"  port_range        ="1/65535"  priority          =1  security_group_id = alicloud_security_group.default.id
  cidr_ip           ="0.0.0.0/0"}

网络相关的配置准备完成后我们接下来配置密钥对,通过密钥对来访问操作服务器,我们先在本地生成密钥对,存储到 scripts 下,方便后续使用

mkdir scripts
ssh-keygen


编写密钥对相关的描述,命名为 operator,并且指定公钥所在的路径

用到了 file() ,terraform 内置的文件读取函数


resource "alicloud_ecs_key_pair""operator" {
  key_pair_name ="operator"  public_key  = file("./scripts/id_rsa.pub")
}

密钥对描述之后,解下来我们需要描述实例,这里我们描述了 ecs 的型号以及镜像,并且绑定了之前定义的 vpc 跟安全组。

这里我们没有对付费方式、使用的磁盘大小、内网IP、公网IP 进行描述,这些都有默认值的,可以在 apply 之前执行 terraform plan查看,有些字段在实例创建后会自动生成。

TIPS:

  1. 上述提到可以跳过的 VPC 安全组配置,可以在该处指定
  2. internet_max_bandwidth_out 设置为 10 会自动生成 ECS 的公网 IP


resource "alicloud_instance""instance" {
  count              = var.instance_count
  availability_zone  = var.zone
  security_groups    = alicloud_security_group.default.*.id
  instance_type        = var.ecs_type
  system_disk_category ="cloud_efficiency"  image_id             = var.image_id
  vswitch_id = alicloud_vswitch.vsw.id
  internet_max_bandwidth_out =10}


既然 ECS 实例我们已经进行了描述,密钥对也进行了描述,那么他们两个需要一个媒介进行关联,那就是 alicloud_ecs_key_pair_attachment资源,由于我们 instance 可能多个,这里我们通过 * 匹配

resource "alicloud_ecs_key_pair_attachment""attach" {
  key_pair_name = alicloud_ecs_key_pair.operator.key_pair_name
  instance_ids  = alicloud_instance.instance.*.id
}

我们对于云资源的描述基本就完成了,实例创建完成后需要初始化我们期望的是并且自动注册到我们的中心节点,alicloud_instance中也提供了 user_data字段,来让我们通过 cloud_init 的方式去在实例初始化时候执行脚本,这也是最优的一种选择。

但是对我们现在的实例来说,k3s-agent 在初始化过程中需要 public_ip, 走 cloud_init 的方式并不是很合适。所以我们通过 remote-exec或者是 ecs_command的方式来搞定。


第一种方式是使用 provisioner  在初始化完成后执行 ssh 链接并执行初始化命令,我们利用到了 null_resource来承载 provisioner,可以看到有如下三个部分:

  1. connection: 配置 ssh 链接,其中我们通过之前生成的 ssh key 来链接
  2. provisioner file: 将本地脚本拷贝到远端服务器,通过 connection 承载链接链路
  3. provisioner remote-exec: 执行远端命令


resource "null_resource""k3s-agent-install" {
  count = var.instance_count
  connection {
    type     ="ssh"    user     ="root"    private_key = file("./scripts/id_rsa")
    host     ="${element(alicloud_instance.instance.*.public_ip, count.index)}"  }
  provisioner "file" {
    content     = format(file("./scripts/k3s-agent-install.sh"), "${element(alicloud_instance.instance.*.private_ip, count.index)}", "${element(alicloud_instance.instance.*.public_ip, count.index)}")
    destination ="/root/k3s-agent-install.sh"  }
  provisioner "remote-exec" {
    inline = [
"chmod +x /root/k3s-agent-install.sh",
"sh -c /root/k3s-agent-install.sh",
    ]
  }
}

可以看到上述使用到了安装脚本,我们这边来配置下安装脚本,其中 private_ip以及 public_ip作为输入参数

TIPS: 需要注意下 format 的值,%s 是占位符,用到的 %需要转义 %%

#!/bin/bashapt-get update
apt-get install wireguard -yhostnamectl set-hostname node-$(echo "%s" | awk -F. '{printf("%%03d%%03d%%03d%%03d",$1,$2,$3,$4)}')exportK3S_TOKEN=<your_k3s_token>
exportK3S_URL=<your_k3s_server_path>
exportINSTALL_K3S_MIRROR=cn
exportK3S_EXTERNAL_IP=%s
exportINSTALL_K3S_EXEC="--token $K3S_TOKEN --server $K3S_URL --node-external-ip $K3S_EXTERNAL_IP  --node-ip $K3S_EXTERNAL_IP --kube-proxy-arg proxy-mode=ipvs masquerade-all=true --kube-proxy-arg metrics-bind-address=0.0.0.0"curl-sfL http://rancher-mirror.cnrancher.com/k3s/k3s-install.sh | sh-

(可选)第二种方式是 ecs_command 的方式,我们可以通过如下方式来配置云助手的 ecs command,这样可以免密创建命令,实例创建完成后我们登陆到云助手执行命令即可。

resource "alicloud_ecs_command""k3s_install" {
  name            ="tf-init-k3s"  command_content = base64encode(format(file("./k3s-agent-install.sh"), alicloud_instance.instance.private_ip, alicloud_instance.instance.public_ip))
  type            ="RunShellScript"  working_dir     ="/root"}


执行部署及校验

编写完资源描述后,我们执行如下命令对于需要的模块初始化, 然后执行计划,对编写的配置进行校验,以及查看预期输出的值,上面我们配置的实例数量是 2,所以可以清晰的看到两个实例的执行计划

terraform init --upgradeterraform plan


执行 并确认, 可以看到资源在创建中,并且已经开始 ssh 进行初始化

terraform apply


此时我们从中心集群查看,节点已经成功注册上来,并且 ready 可以被调度了,全程自动化


此时我们查看一下云资源

如果节点不需要使用了,可以直接通过 terraform 一键销毁我们创建的资源

terraform destory



ECS 与 ECI 的碰撞

依托于 ECS 的超高稳定性以及强劲的性能,云上的弹性 ECI 应运而生,借着评测的机会我们将实操 ECS 部署的 K3s 集群接入 ECI。


首先我们来到 ECI ,创建 vNode,这里我们需要提供 vpc,vsw 以及 安全组相关信息,这里需要我们填写访问集群的 kubeconfig,可以从中心集群的 ~/.kube/config 获取。

填写 kubeconfig 时候注意 server 地址,这里我们填写内网地址,通过如下命令获取,解析来介绍如何添加路由。


kubectl get svc kubernetes

image.png

由于上面我们走的内网,需要添加一下路由,选择上述配置的专有网络,进入到自定义路由,把 apiserver 的 service 网段添加进去(不同方式搭建的 kubernetes 查找方式不同,k3s 默认就是  10.43.0.0/24

image.png

如果你期望 ECI 可以反向访问你的 Kubernetes 集群的话,可以将不同节点的路由,手动添加到路由表中,并且设置该主机作为下一跳,具体路由信息可以通过如下命令获取:

kubectl get no your_node -o yaml | grep-i podCIDR: | awk'{print $2}'


添加完成后我们提交 vnode 配置,可以在集群中看到 virtual-kubelet agent 已经 ready 了

image.png

image.png


接下来我们部署 eci-profile 组件,通过该组件我们可以编排 pod 调度到 eci 的规则以及规格等,参考官方文档,我们编写 eci-profile.yaml 并部署,等待组件起来。

kubectl apply -f eci-profile.yaml

image.png


从官方文档中我可以得到,默认 namespace 的筛选规则如下,只要 namespace 包含该 label pod 默认就会调度到 eci

image.png


我们此时编写一个简单的 demo,调度到 eci 上

apiVersion: v1
kind: Namespace
metadata:  name: eci-test
  labels:    alibabacloud.com/eci: "true"---apiVersion: apps/v1
kind: Deployment
metadata:  name: gin-demo
  namespace: eci-test  
spec:  replicas: 1  selector:    matchLabels:      app: gin-demo
  template:    metadata:      labels:        app: gin-demo
      name: gin-demo
    spec:      containers:      - image: registry-vpc.cn-shanghai.aliyuncs.com/viper/gin-demo:v0.2
        imagePullPolicy: IfNotPresent
        name: gin-demo
---apiVersion: v1
kind: Service
metadata:  name: gin-demo-service
  namespace: eci-test
spec:  ports:  - port: 60000    targetPort: 60000  selector:    app: gin-demo

部署过后,我们可以查看调度到的节点的确是 eci,并且可以在 eci 中查看到

image.png

image.png


ECI 只有在运行的时候按照占用的资源收费,费用很低很低,非常适合跑一些临时的任务或者应对一些弹性扩容的场景,如果你有一些有状态的服务想要跑上去,没问题的!可以参考文章上面介绍的基于 nas 的 csi-provisoner 部署,ECI 配 NAS 如鱼得水。


全方位监控告警体系建设

上面几个部分我们针对基于 ECS 构建的集群的配置以及应用部署进行了讲解,在本部分我们将在之前的基础上构建关于 应用/节点/云资源 监控告警。我们将基于 prometheus 生态技术栈入手,配合阿里云云监控体系构建高保障的体系。


Prometheus stack 部署

这里我们使用 prometheus stack 的包,里面包含了 prometheus、alertmanager、kube-state-metrics、grafana 等组件,可以免去非常多组件部署的烦恼。


首先我们添加 chart 仓库

helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update


接下来我们编写配置文件

参数

解释

prometheusOperator

prometheus operator 相关配置,这里我用了 acr 中的镜像,chart 版本是 kube-prometheus-stack-35.0.3 ,其他版本需要自己替换

prometheus,alertmanager

prometheus,alertmanager 相关配置我们只配置持久化即可,可以使用我们上面介绍的几种存储的任一 strorageClass, 这里我使用 nfs-client

grafana

grafana 我们也将存储持久化,并且开放了公网地址


prometheusOperator:  admissionWebhooks:    patch:       image:         repository: registry.cn-shanghai.aliyuncs.com/viper/kube-webhook-certgen
kube-state-metrics:  image:    repository: registry.cn-shanghai.aliyuncs.com/viper/kube-state-metricis
prometheus:  prometheusSpec:    storageSpec:      volumeClaimTemplate:        spec:          storageClassName: nfs-client
          accessModes: ["ReadWriteOnce"]          resources:            requests:              storage: 50Gi
alertmanager:  alertmanagerSpec:    storage:      volumeClaimTemplate:        spec:          storageClassName: nfs-client
          accessModes: ["ReadWriteOnce"]          resources:            requests:              storage: 50Gi
grafana:  ingress:    enabled: true    hosts:    - <your_domain> 
  persistence:    enabled: true    storageClassName: nfs-client

配置完成后,我们执行如下命令部署,所有配置我们放到了 monitor-system 下

helm upgrade --install prometheus-stack  kube-prometheus-stack-35.0.3.tgz -n monitor-system --create-namespace-f values.yaml
kubectl get po -n monitor-system


告警配置

部署完成后,我们通过如下命令获取 grafana 初始化密码

kubectl get secret -n monitor-system prometheus-stack-grafana -ojsonpath={'.data.admin-password'} | base64 -d

接下来我们访问 grafana,可以看到默认已经配置了从 ECS 机器监控,到 Kubnernetes 监控的模板


我们来看一下节点相关的数据,几乎覆盖了常见的机器指标


对于监控告警也是必不可少的,我们就以上面实践场景中的 blog 作为应用监控告警的案例,由于我们使用了 prometheus operator,所以我们需要创建 promrule 资源来描述告警规则

  • 其中我们通过 PromQL描述了 blog-system下的 pod,如果 cpu 已使用的值 / 配置的 cpu limit 值 超过了 90%,则触发告警
  • 其中按照 namespace pod 的格式触发告警


apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:  labels:    group: applications
    release: prometheus-stack
    app: kube-prometheus-stack
  name: prometheus-custom-applications.rules
  namespace: monitor-system
spec:  groups:  - name: blog-rules
    rules:    - alert: cpu_usage
      annotations:        description: 应用 {{$labels.namespace}}/{{$labels.pod}} CPU 大于阈值
        summary: cpu 当前使用值 {{ $value }}      expr: |-
        100 * max(rate(container_cpu_usage_seconds_total{namespace="blog-system"}[5m])/ on (container, pod) kube_pod_container_resource_limits{namespace="blog-system", resource="cpu"}) by (pod) > 90
      for: 1m
      labels:        application: blog
        severity: warning


部署以后我们可以通过如下命令查看已经存在的 prometheus 规则

TIPS: 可以看到默认 stack 中包含了非常多的基础告警规则

kubectl get promrule -n monitor-system


稍等一会等待同步,我们可以在 grafana 中的 Alert rules 查看到新增加的规则

TIPS: 这里默认对接的都是 prometheus 的数据源,同样可以登录到 prometheus 查看


(可选)配置钉钉告警,默认 alertmanager 是不支持钉钉告警的,我们可以通过 prometheus-webhook-dingtalk 作为转换层。


首先我们 clone 代码、配置并部署


git clone https://github.com/timonwong/prometheus-webhook-dingtalk
cd prometheus-webhook-dingtalk/contrib/k8s/
vim config/config.yaml 
# 编辑 targets,如下,mention 代表是不是 @ 指定人/所有人targets:
  webhook_mention_all:
    url: https://oapi.dingtalk.com/robot/send?access_token=xxx
    secret: your_dingtalk_secret
    mention:
      all: true# 结束编辑kubectl kustomize | kubectl apply -f-


其中钉钉的 webhook 需要群里中创建机器人,安全设置是必须的,这里我们选择的是 secret



部署完成后,我们需要配置 dingtalk 的 reciver 并将指定规则的告警发送到 dingtalk

  • 配置了新的 receiver 叫做 dingtalk,application=blog 的会发送到这个 recevier
  • digntalk 的 webhook 地址指向 prometheus-webhook-dingtalk ,由于 monitor 相关的都在同一个 namespace 下,直接配置 service


apiVersion: monitoring.coreos.com/v1alpha1
kind: AlertmanagerConfig
metadata:  name: dingtalk
  namespace: monitor-system
spec:  route:    receiver: dingtalk
    matchers:    - name: application
      value: blog
  receivers:  - name: dingtalk
    webhookConfigs:    - url: http://alertmanager-webhook-dingtalk/dingtalk/webhook_mention_all/send


上述 amcfg 部署后,我们可以在 alertmanager 中查看,prometheus operator 会 merge AlertManagerConfig


由于安全问题,我们没有开放 alertmanager 的 ingress, 我们本地配置好集群的 kubeconfig,使用 kubectl 将远端的 service 转发到本地访问

kubectl -n monitor-system port-forward svc/prometheus-stack-kube-prom-alertmanager 8081:9093


直接访问本地 http://localhost:8081,查看 Status 可以如下图所示,dingtalk 配置已经加入了


此时我们可以进入到 blog的容器中,执行如下命令,让他的 cpu 直接跑满

for i in`seq 1 $(cat /proc/cpuinfo |grep "physical id" |wc -l)`; do dd if=/dev/zero of=/dev/null & done


可以在 grafana 中查看到该容器的 cpu


此时我们查看 prometheus 的 alert 状态(Inactive-> Pending -> Firing)以及钉钉群的告警,告警通知成功。同时我们还可以看到默认 stack 也配置了对于 pod cpu 的告警


prometheus 还是非常值得去研究一下的,这里只是在搭建完成监控体系的基础上,做了一些小的演示,大家有兴趣可以去深入研究下。



云资源告警

上一个部分我们引入了在 ECS 之上的 机器/应用 层面的告警,这个可以 cover 大部分的场景,但是有些极端场景,导致我们的监控体系崩溃,机器瘫痪,我们需要其他的监控来告知。这就需要我们使用阿里云对于云资源的监控告警,相当于在我们最后的保险

我们来到云监控,可以看到我们指定区域的 ecs 是否已经部署了监控客户端,我们可以选择手动部署或者批量部署,建议勾选新的 ECS 都自动安装上监控组件



我们直接批量安装,等待监控组件正常启动


接下来我们验证一下勾选后,新创建的 ECS 是否会自动部署 Agent,我们使用之前的 terraform新创建一下机器,切换 region 以后,可以看到新起来的 ECS 有部署 Agent 的。



我们解析来看一下告警规则,ECS 支持机器层面非常详细的监控指标,可以满足大部分的场景


并且支持多种联系人通知方式,大家可以参考一下文档


总结

到这里,基于 ECS 的云端开发/协同办公 集群就已经介绍的差不多了,由于是 ECS 的评测我们手里资源不多情况下使用了 k3s 作为基石,对于上述的内容,均可以在 Kubernetes 上实现。而且机器不仅仅限于 ECS,我个人的集群中大部分都是活动时候买的轻量服务器,看到是不是已经迫不及待了,快动起手来,打造你的远端 “军火库”。

相关实践学习
一小时快速掌握 SQL 语法
本实验带您学习SQL的基础语法,快速入门SQL。
7天玩转云服务器
云服务器ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,可降低 IT 成本,提升运维效率。本课程手把手带你了解ECS、掌握基本操作、动手实操快照管理、镜像管理等。了解产品详情:&nbsp;https://www.aliyun.com/product/ecs
目录
相关文章
|
2月前
|
存储 边缘计算 监控
【MODBUS】Modbus主站云端服务器和边缘设备部署区别
【MODBUS】Modbus主站云端服务器和边缘设备部署区别
37 0
|
2月前
|
存储 资源调度 应用服务中间件
浅谈本地开发好的 Web 应用部署到 ABAP 应用服务器上的几种方式
浅谈本地开发好的 Web 应用部署到 ABAP 应用服务器上的几种方式
27 0
|
4月前
|
人工智能 Serverless 数据安全/隐私保护
云端服务器应用实践:函数计算X 通义千问快速部署 AI 个人助手应用
云端服务器应用实践:函数计算X 通义千问快速部署 AI 个人助手应用
330 2
|
4月前
|
缓存 网络协议 Linux
Linux C/C++ 开发(学习笔记十三):百万并发的服务器实现
Linux C/C++ 开发(学习笔记十三):百万并发的服务器实现
55 0
|
3月前
|
网络协议 IDE 网络安全
GoLand远程开发IDE:使用SSH远程连接服务器进行云端编程
GoLand远程开发IDE:使用SSH远程连接服务器进行云端编程
102 0
|
5月前
|
小程序 PHP
微信公众号开发(一)打通服务器与微信之间的通信
说来惭愧PHP做了这么久,好像就没有从头开发过一个微信公众号,这次刚好有机会从头接入开发一个完整的公众号,也不能说完整,但是这些微信的接口我基本上都试一试~看看大概是什么情况。 首先:打通服务器与微信之间的通信。
56 0
|
4月前
|
网络协议 Linux C++
Linux C/C++ 开发(学习笔记十二 ):TCP服务器(并发网络编程io多路复用epoll)
Linux C/C++ 开发(学习笔记十二 ):TCP服务器(并发网络编程io多路复用epoll)
59 0
|
5月前
|
前端开发 应用服务中间件 nginx
Next.js 创建项目到服务器部署(目录结构介绍、项目结构Demo、开发细节注意)
Next.js 创建项目到服务器部署(目录结构介绍、项目结构Demo、开发细节注意)
390 0
|
5月前
|
移动开发 前端开发 JavaScript
VSCode设置类似Webstorm那样可以用本地局域网IP地址访问自己开发的测试项目,vs code 前端如何以服务器模式打开?
VSCode设置类似Webstorm那样可以用本地局域网IP地址访问自己开发的测试项目,vs code 前端如何以服务器模式打开?
VSCode设置类似Webstorm那样可以用本地局域网IP地址访问自己开发的测试项目,vs code 前端如何以服务器模式打开?
|
4月前
|
网络协议 Linux C++
Linux C/C++ 开发(学习笔记十一 ):TCP服务器(并发网络网络编程 一请求一线程)
Linux C/C++ 开发(学习笔记十一 ):TCP服务器(并发网络网络编程 一请求一线程)
39 0