Kubernetes初探[1]:部署你的第一個ASP.NET Core應用到k8s集群

来源:https://www.cnblogs.com/RainingNight/archive/2019/01/08/first-aspnetcore-app-in-k8s.html
-Advertisement-
Play Games

Kubernetes簡介 Kubernetes是Google基於Borg開源的容器編排調度引擎,作為CNCF(Cloud Native Computing Foundation)最重要的組件之一,它的目標不僅僅是一個編排系統,而是提供一個規範,可以讓你來描述集群的架構,定義服務的最終狀態,Kuber ...


Kubernetes簡介

Kubernetes是Google基於Borg開源的容器編排調度引擎,作為CNCF(Cloud Native Computing Foundation)最重要的組件之一,它的目標不僅僅是一個編排系統,而是提供一個規範,可以讓你來描述集群的架構,定義服務的最終狀態,Kubernetes可以幫你將系統自動得達到和維持在這個狀態。

更直白的說,Kubernetes可以讓用戶通過編寫一個yaml或者json格式的配置文件,也可以是通過工具/代碼生成或者是直接請求Kubernetes API來創建應用,該配置文件中包含了用戶想要應用程式保持的狀態,不管整個Kubernetes集群中的個別主機發生什麼問題,都不會影響應用程式的狀態,你還可以通過改變該配置文件或請求Kubernetes API來改變應用程式的狀態。

這意味著開發人員不需要在意節點的數目,也不需要在意從哪裡運行容器以及如何與它們交流。開發人員也不需要管理硬體優化,或擔心節點關閉(它們將遵循墨菲法則),因為新的節點會添加到Kubernetes集群,同時Kubernetes會在其他運行的節點中添加容器,Kubernetes會發揮最大的作用。

總結:Kubernetes是容器控制平臺,可以抽象所有的底層基礎設施(容器運行用到的基礎設施)。

Kubernetes——讓容器應用進入大規模工業生產。

Kubernetes另一個深入人心的特點是:它標準化了雲服務提供商。比如,有一個Azure、Google雲平臺或其他雲服務提供商的專家,他擔任了一個搭建在全新的雲服務提供商的項目。這可能引起很多後果,比如說:他可能無法在截止期限內完成;公司可能需要招聘更多相關的人員,等等。相對的,Kubernetes就沒有這個問題。因為不論是哪家雲服務提供商,你都可以在上面運行相同的命令,以既定的方式向Kubernetes API伺服器發送請求,Kubernetes會負責抽象,併在不同的雲服務商中實現。

對於公司來說,這意味著他們不需要綁定到任何一家雲服務商。他們可以計算其他雲服務商的開銷,然後轉移到別家,並依舊保留著原來的專家,原來的人員,他們還可以花更少的錢。

Pod

Kubernetes有很多技術概念,同時對應很多API對象,最重要的也是最基礎的對象就是Pod。Pod是Kubernetes集群中運行部署應用的最小單元,並且是支持多個容器的。

Pod的設計理念是支持多個容器在一個Pod中共用網路地址和文件系統,可以通過進程間通信和文件共用這種簡單高效的方式組合完成服務。Pod對多容器的支持是Kubernetes最基礎的設計理念。比如你運行一個操作系統發行版的軟體倉庫,一個Nginx容器用來發佈軟體,另一個容器專門用來從源倉庫做同步,這兩個容器的鏡像不太可能是一個團隊開發的,但是他們一塊兒工作才能提供一個微服務;這種情況下,不同的團隊各自開發構建自己的容器鏡像,在部署的時候組合成一個微服務對外提供服務。不過,在大多數情況下,我們只會在Pod中運行一個容器,本文中的例子也是這樣的。

Pod 的另一個特征是:如果我們希望使用其他 RKE 等技術的話,我們可以做到不依賴Docker容器。

Docker是kubernetes中最常用的容器運行時,但是Pod也支持其他容器運行時。

總的來說,Pod的主要特征包括:

  • 每個Pod可以在Kubernetes集群內擁有唯一的IP地址;

  • Pod可以擁有多個容器。這些容器共用同一個埠空間,所以他們可以通過localhost交流(可想而知它們無法使用相同的埠),與其他Pod內容器的交流可以通過結合Pod的IP來完成;

  • 一個Pod內的容器共用同一個捲、同一個 IP、埠空間、IPC 命名空間。

定義一個Pod

如下,我們定義一個最簡單的Pod:

apiVersion: v1
kind: Pod # 定義Kubernetes資源的類型為Pod
metadata:
  name: demo-web # 定義資源的名稱
  labels: # 為Pod貼上標簽,後面會介紹其用處
    app: demo-web
spec: # 定義資源的狀態,對於Pod來說,最重要屬性就是containers
  containers: # containers一個數組類型,如果你希望部署多個容器,可以添加多項
    - name: web # 定義本Pod中該容器的名稱
      image: rainingnight/aspnetcore-web # 定義Pod啟動的容器鏡像地址
      ports:
        - containerPort: 80 # 定義容器監聽的埠(與Dockerfile中的EXPOSE類似,只是為了提供文檔信息)

然後保存,我這裡命名為demo-web-pod.yaml

現在我們可以在終端中輸入以下命令來創建該Pod:

kubectl create -f demo-web-pod.yaml

# 輸出
# pod/demo-web created

可以使用如下命令,來查看kubernetes中的Pod列表:

kubectl get pods

# 輸出
# NAME                           READY   STATUS    RESTARTS   AGE
# demo-web                       1/1     Running   0          65s

如果該Pod還處於ContainerCreating狀態的話,你可以在運行命令的時候加入--watch參數,這樣當Pod變成運行狀態的時候,會自動顯示在終端中。

訪問應用程式

在上面,我們成功部署了一個ASP.NET Core Mvc程式的Pod,那麼如何訪問它呢?如果只是為了調試,我們可以使用轉髮端口的方式來快速訪問:

kubectl port-forward demo-web 8080:80

# 輸出
# Forwarding from 127.0.0.1:8080 -> 80

然後我們再瀏覽器中訪問:127.0.0.1:8080,顯示如下:

aspnetcore-web

如上,還展示了Pod的主機名和IP,這是因為我在應用中添加瞭如下代碼:

public void OnGet()
{
    HostName = Dns.GetHostName();
    HostIP = Dns.GetHostEntry(HostName).AddressList.FirstOrDefault(x => x.AddressFamily == AddressFamily.InterNetwork).ToString();
}

不過,埠轉發的方式只能在本機訪問,為了從外部訪問應用程式,我們需要創建Kubernetes中的另外一種資源:Service

Service

Kubernetes中的Service資源可以作為一組提供相同服務的Pod的入口,這個資源肩負發現服務和平衡Pod之間負荷的重任。

在Kubernetes集群中,我們擁有提供不同服務的Pod,那麼Service如何知道該處理哪個Pod呢?

這個問題就用標簽來解決的,具體分兩個步驟:

  • 給所有需要Service處理的對象Pod貼上標簽。
  • 在Service中使用一個選擇器(Label Selector),該選擇器定義了所有貼有對應的標簽的對象Pod。

標簽

標簽提供了一種簡單的方法用於管理Kubernetes中的資源。它們用一對鍵值表示,且可以用於所有資源。

其實在上面的Pod定義中,我們已經定義了標簽:

metadata:
  name: demo-web
  labels:
    app: demo-web

如上,我們為Pod附加了標簽app:demo-web,在查看Pod的時候,可以使用--show-labels參數來顯示Pod對應的標簽:

kubectl get pods --show-labels

# 輸出
# NAME                           READY   STATUS    RESTARTS   AGE     LABELS
# demo-web                       1/1     Running   0          1m52s   app=demo-web

可以看到,我們的Pod都擁有一個app=demo-web標簽。

定義Service

現在,讓我們為剛纔創建的Pod定義一個Service:

apiVersion: v1
kind: Service # 定義Kubernetes資源的類型為Service
metadata:
  name: demo-web-service # 定義資源的名稱
spec:
  selector: # 指定對應的Pod
    app: demo-web # 指定Pod的標簽為demo-web
  ports:
  - protocol: TCP # 協議類型
    port: 80 # 指定Service訪問的埠
    targetPort: 80 # 指定Service轉發請求的埠
    nodePort: 30000
  type: NodePort # 指定Service的類型,在這裡使用NodePort來對外訪問

如上,我們使用selector屬性來選擇相應的標簽,並把服務類型(type)設置為NodePorttype的取值有以下4種:

  • ClusterIP:預設值,通過集群的內部IP暴露服務,該模式下,服務只能夠在集群內部可以訪問。

  • NodePort:通過每個Node上的IP和靜態埠(NodePort)暴露服務,NodePort服務會路由到ClusterIP服務,這個ClusterIP服務會自動創建。

  • LoadBalancer:使用雲提供商的負載均衡器,可以向外部暴露服務,外部的負載均衡器可以路由到NodePort服務和ClusterIP服務。

  • ExternalName:通過返回CNAME和它的值,可以將服務映射到externalName欄位的內容(如:foo.bar.example.com)。沒有任何類型代理被創建,這隻有 Kubernetes 1.7 或更高版本的kube-dns才支持。

對於服務類型我們先瞭解這麼多就可以了,後續會再來詳細介紹。

然後使用如下命令創建Service:

kubectl create -f demo-web-service.yaml

# 輸出
# service/demo-web-service created

使用如下命令來檢查服務的狀態:

kubectl get services

# 輸出
# NAME               TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
# demo-web-service   NodePort    10.105.132.214   <none>        80:30000/TCP   10s

如上,它有一個CLUSTER-IP為10.105.132.214,因此我們可以在集群內使用10.105.132.214:80來訪問該服務,如果是在集群外部,可以使用NodeIP:30000來訪問。

服務發現與負載均衡

在上面我們說到,Service肩負著發現服務和平衡Pod之間負荷的重任,那它是怎麼做的呢?讓我們先再添加一個Pod:

apiVersion: v1
kind: Pod
metadata:
  name: demo-web-copy
  labels:
    app: demo-web
spec:
  containers:
    - name: web
      image: rainingnight/aspnetcore-web      
      ports:
        - containerPort: 80

如上,其定義與之前的Pod一樣,只是把name改成了demo-web-copy,然後創建Pod:

kubectl create -f demo-web-copy.pod.yaml

# 查看Pod
kubectl get pods

# 輸出
# NAME                           READY   STATUS    RESTARTS   AGE
# demo-web                       1/1     Running   0          10m
# demo-web-copy                  1/1     Running   0          29s

現在我們使用NodeIP:30000來訪問,打開兩個瀏覽器視窗,多刷新幾次,以便讓它們分別路由到不同的Pod,最終顯示如下:

aspnetcore-web-service

可以看到,我們新創建的Pod已經通過Servie來接受請求了,不需要修改成任何程式代碼,Kubernetes就已經幫我們實現了服務發現和負載均衡,是不是非常爽。

Deployment

在上面我們手動部署了兩個Pod,但是這隻是單機的玩法,它與直接使用Docker容器相比並無太大優勢,如果我們需要部署一千個實例,那就是一個痛苦的過程,或者我們又想快速更新和迅速回滾,這根本就是不可能的!

其實在k8s中,我們很少直接使用Pod,更多的是使用Kubernetes的另外一種資源:Deployment

Deployment表示用戶對Kubernetes集群的一次更新操作。可以是創建一個新的服務或是更新一個新的服務,也可以是滾動升級一個服務。Deployment可以幫助每一個應用程式的生命都保持相同的一點:那就是變化。此外,只有掛掉的應用程式才會一塵不變,否則,新的需求會源源不斷地涌現,更多代碼會被開發出來、打包以及部署,這個過程中的每一步都有可能出錯。Deployment可以自動化應用程式從一版本升遷到另一版本的過程,並保證服務不間斷,如果有意外發生,它可以讓我們迅速回滾到前一個版本。

Deployment定義

現在,我們使用Deployment來部署我們的Pod,並實現在部署期間服務不間斷服務,可以如下定義:

apiVersion: apps/v1
kind: Deployment # 定義Kubernetes資源的類型為Deployment
metadata:
  name: demo-web-deployment # 定義資源的名稱
  labels:
    app: demo-web-deployment
spec:  # 定義資源的狀態。
  replicas: 2 # 定義我們想運行多少個Pod,在這裡我們希望運行2個
  selector:
    matchLabels: # 定義該部署匹配哪些Pod
      app: demo-web
  minReadySeconds: 5 # 可選,指定Pod可以變成可用狀態的最小秒數,預設是0
  strategy: # 指定更新版本時,部署使用的策略
    type: RollingUpdate # 策略類型,使用RollingUpdate可以保證部署期間服務不間斷
    rollingUpdate:
      maxUnavailable: 1 # 部署時最大允許停止的Pod數量(與replicas相比)
      maxSurge: 1 # 部署時最大允許創建的Pod數量(與replicas相比)
  template: # 用來指定Pod的模板,與Pod的定義類似
    metadata:
      labels: # 根據模板創建的Pod會被貼上該標簽,與上面的matchLabels對應
        app: demo-web
    spec:
      containers:
        - name: web
          image: rainingnight/aspnetcore-web
          imagePullPolicy: Always # 預設是IfNotPresent,如果設置成Always,則每一次部署都會重新拉取容器映像(否則,如果本地存在指定的鏡像版本,就不會再去拉取)
          ports:
            - containerPort: 80

保存為demo-web-deployment.yaml,然後輸入以下命令來創建Deployment:

kubectl create -f demo-web-deployment.yaml

# 輸出
# deployment.apps/demo-web-deployent created

現在我們再來查看以下Pod:

kubectl get pods

# 輸出
# NAME                                   READY   STATUS    RESTARTS   AGE
# demo-web                               1/1     Running   0          4h28m
# demo-web-copy                          1/1     Running   0          18m
# demo-web-deployment-745f7997c4-d24bb   1/1     Running   0          16s
# demo-web-deployment-745f7997c4-jk9jn   1/1     Running   0          16s

如上,我們有4個運行中的Pod,其中前二個是我們手動創建的,其他兩個是使用Deployment創建的。

我們可以使用kubectl delete pod <pod-name>刪除一個Deployment創建的Pod,看看結果會怎樣:

kubectl delete pod demo-web-deployment-745f7997c4-d24bb

# 輸出
# pod "demo-web-deployment-745f7997c4-d24bb" deleted

再次查看Pod列表:

kubectl get pods

# 輸出
# NAME                                   READY   STATUS    RESTARTS   AGE
# demo-web                               1/1     Running   0          31m
# demo-web-copy                          1/1     Running   0          22m
# demo-web-deployment-745f7997c4-jk9jn   1/1     Running   0          3m39s
# demo-web-deployment-745f7997c4-mrrw6   1/1     Running   0          11s

可以看到,又重新創建了一個Pod:demo-web-deployment-745f7997c4-mrrw6,Deployment會監控我們的Pod數量,保持為我們預期的個數。

零停機時間部署(Zero-downtime)

現在我們嘗試以下零停機部署,首先修改Deployment中的image為:rainingnight/aspnetcore-web:1.0.0,然後運行如下命令:

kubectl apply -f demo-web-deployment.yaml --record

# 輸出
# deployment.apps/demo-web-deployment configured

將kubectl的--record設置為true可以在annotation中記錄當前命令創建或者升級了該資源。這在未來會很有用,例如,查看在每個 Deployment revision 中執行了哪些命令。

除了修改yaml外,還可以直接運行kubectl set image deployment demo-web-deployment web=rainingnight/aspnetcore-web:1.0.0 --record來達到同樣的效果。

然後使用如下命令檢查服務更新狀態:

kubectl rollout status deployment demo-web-deployment

# 輸出
# Waiting for deployment "demo-web-deployment" rollout to finish: 1 old replicas are pending termination...
# Waiting for deployment "demo-web-deployment" rollout to finish: 1 old replicas are pending termination...
# Waiting for deployment "demo-web-deployment" rollout to finish: 1 old replicas are pending termination...
# Waiting for deployment "demo-web-deployment" rollout to finish: 1 old replicas are pending termination...
# Waiting for deployment "demo-web-deployment" rollout to finish: 1 of 2 updated replicas are available...
# Waiting for deployment "demo-web-deployment" rollout to finish: 1 of 2 updated replicas are available...
# deployment "demo-web-deployment" successfully rolled out

如上可以看到,新版本已經成功上線,併在這個過程中副本被逐個替換,也就意味著應用程式始終線上。

現在我們刷新一下瀏覽器,可以看到標題已經變成了Home page - Web-v1:

回滾到前一個狀態

如果突然發現新上線的版本有Bug,需要緊急回滾到上一個版本,那對Kubernetes來說也是非常簡單的。

我們首先運行如下命令來查看歷史版本:

kubectl rollout history deployment demo-web-deployment

# 輸出
# deployment.extensions/demo-web-deployment 
# REVISION  CHANGE-CAUSE
# 1         <none>
# 2         kubectl apply --filename=demo-web-deployment.yaml --record=true

如上,可以看到有2條歷史,那麼為什麼第1條的CHANGE-CAUSE<none>呢,這就是因為我們第二次部署的時候使用了--record=true參數。現在,我們想回滾到第一個版本,只需運行如下命令:

kubectl rollout undo deployment demo-web-deployment --to-revision=1

# 輸出
# deployment.extensions/demo-web-deployment rolled back

再次刷新瀏覽器,標題又變回了Home page - Web

部署多個應用

現在我們再部署一個ASP.NET Core WebApi程式,併在剛纔的Web應用中調用它,形成一個最簡單的微服務模式。

部署WebApi

與前面的Web應用的部署類似,就不用過多介紹,定義如下YAML:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: demo-api-deployment
  labels:
    app: demo-api-deployment
spec:
  replicas: 2
  selector:
    matchLabels:
      app: demo-api
  minReadySeconds: 5
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 1
      maxSurge: 1
  template:
    metadata:
      labels:
        app: demo-api
    spec:
      containers:
        - name: api
          image: rainingnight/aspnetcore-api
          imagePullPolicy: Always
          ports:
            - containerPort: 80

然後創建Deployment:

kubectl create -f demo-api-deployment.yaml 

查看部署情況:

kubectl get pods

# 輸出
# NAME                                   READY   STATUS    RESTARTS   AGE
# demo-api-deployment-66575d644-9wk7g    1/1     Running   0          75s
# demo-api-deployment-66575d644-fknpx    1/1     Running   0          75s
# demo-web-deployment-745f7997c4-h7fr8   1/1     Running   0          9m23s
# demo-web-deployment-745f7997c4-kvptm   1/1     Running   0          9m23s

前面手動創建的2個Pod已經被我刪除了,因為用Deployment創建的Pod就好了。

現在我們為Api應用也創建一個Service,以便在Web應用中訪問它:

apiVersion: v1
kind: Service
metadata:
  name: demo-api-service
spec:
  selector:
    app: demo-api
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80

因為我們的Api應用是不需要在集群外部訪問的,因此服務類型(type)不需要設置,使用預設的ClusterIP就可以了。

部署Servcie:

kubectl create -f demo-api-service.yaml

然後查看Servie:

kubectl get services

# 輸出
# NAME               TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
# demo-api-service   ClusterIP   10.111.25.49     <none>        80/TCP         26s
# demo-web-service   NodePort    10.105.132.214   <none>        80:30000/TCP   58m

可以使用瀏覽器來訪問:10.111.25.49/api/values 來驗證一下是否部署成功。

調用服務

那麼,還剩下最後一個問題,我們的Web應用中如何獲取到Api應用的訪問地址呢?

我們先看一下,在Web應用的代碼中是怎麼調用Api的:

// Startup.cs
public void ConfigureServices(IServiceCollection services)
{
    services.AddHttpClient("api", _ => _.BaseAddress = new Uri(Configuration["ApiBaseUrl"]));
}

// FetchData.cshtml
public class FetchDataModel : PageModel
{
    private static HttpClient _client;

    public FetchDataModel(IHttpClientFactory httpClientFactory)
    {
        _client = httpClientFactory.CreateClient("api");
    }

    public IList<WeatherForecast> Forecasts { get; set; }

    public async Task OnGetAsync()
    {
        var res = await _client.GetStringAsync("/api/SampleData/WeatherForecasts");
        Forecasts = JsonConvert.DeserializeObject<IList<WeatherForecast>>(res);
    }
}

如上,我們首先註冊了一個HttpClient,並從配置文件中讀取ApiBaseUrl做為BaseAddress,然後在FetchData頁面中使用HttpClient調用Api服務。

因為在Asp.Net Core中,預設情況下,環境變數中的配置是會覆蓋appsettings.json中的配置的,因此我們可以使用添加環境變數的方式來配置ApiBaseUrl

修改demo-web-deployment.yaml,添加env屬性,如下:

containers:
  - name: web
    image: rainingnight/aspnetcore-web
    imagePullPolicy: Always
    ports:
      - containerPort: 80
    env:
      - name: ApiBaseUrl
        value: "http://10.111.25.49"

然後在Kubernetes中應用該配置:

kubectl apply -f demo-web-deployment.yaml 

等待滾動更新完成,刷新瀏覽器,點擊FetchData菜單:

aspnetcore-web-fetchdata

如上,可以看到數據成功返回,但是直接使用集群IP10.111.25.49,這也有點太低級了,其實我們可以直接使用功能變數名稱:http://demo-api-service,修改後如下:

  env:
    - name: ApiBaseUrl
      value: "http://demo-api-service"

提交到Kubernetes,然後刷新瀏覽器,可以看到完美運行,這是因為CoreDNS(Kube-DNS)幫我們完成了功能變數名稱解析。

在Kubernetes 1.11中,CoreDNS已經實現了基於DNS的服務發現的GA,可作為kube-dns插件的替代品。這意味著CoreDNS將作為各種安裝工具未來發佈版本中的一個選項來提供。事實上,kubeadm團隊選擇將其作為Kubernetes 1.11的預設選項。

CoreDNS是一個通用的、權威的DNS伺服器,提供與Kubernetes後向相容但可擴展的集成。它解決了kube-dns所遇到的問題,並提供了許多獨特的功能,可以解決各種各樣的用例。

DNS伺服器監控kubernetes創建服務的API, 併為每個服務創建一組dns記錄。如果在整個群集中啟用了dns, 所有Pod都會使用它作為DNS伺服器。比如我們的demo-api-service服務,DNS伺服器會創建一條"my-service.my-ns"也就是10.111.25.49:demo-api-service.default的dns記錄,因為我們的Web應用和Api應用在同一個命名空間(default)中,所以可以直接使用demo-api-service來訪問。

總結

本文帶領大家一步一步部署了一個最簡單的ASP.NET Core MVC + WebApi的微服務程式,介紹了Kubernetes中最基本的三個概念:PodDeploymentService,相信大家對Kubernetes也有了一個全面的認識。

雖然Kubernetes整個體系是非常複雜的,但是不用擔心,一開始我們不用去求甚解,最重要的是先跑起來,後續我會和大家一起逐步深入,由簡到繁,愉快的掌握Kubernetes。

附本文所用示例代碼:https://github.com/RainingNight/AspNetCoreDocker

相關資料:


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 官方寫的方法干擾線是固定的 然後找到captcha/helpers.py 在這個文件添加下麵的函數 ...
  • 一.socketserver模塊 1.sockeserver的源碼流程 2.簡單的使用 socketserver服務端 socket客戶端 二.連接的合法性驗證 1.os.urandom(n)加密 os.urandom(n)是一種bytes類型的隨機生成n個位元組字元串,而且每次生成的值都不相同,再加 ...
  • 一、編寫一個簡單程式,要求數組長度為5,分別賦值10,20,30,40,50,在控制台輸出該數組的值。 package com.test; public class t01 { public static void main(String[] args) { // 靜態初始化 int i[] = n ...
  • 前言: 由於導師在我的畢設項目裡加了消息系統(本來想水水就過的..),沒辦法...來稍微研究研究吧..簡單簡單... 需求分析 我的畢設是一個博客系統 ,類似於簡書這樣的,所以消息系統也類似,在用戶的消息里包含了有:喜歡和贊、評論、關註、私信這樣的一類東西,這樣的一個系統應該包含以下的功能: 1. ...
  • 由於 Apache公司發現myBatis的分頁弊端,所以又研發出得補丁:PageHelper 中央倉庫5.1.2版連接地址: <!-- https://mvnrepository.com/artifact/com.github.pagehelper/pagehelper --><dependency ...
  • 變數 什麼是變數 變數就是變化的量,變就是變化,量用於衡量描述對象的狀態 為什麼要有變數 程式執行的本質就是一系列狀態的變化,變是程式執行的直接體現,所以我們需要有一種機制能夠反映或者說是保存下來程式執行時狀態以及狀態的變化。 變數的定義規範 #1.變數名只能是字母、數字或下劃線的組合 #2.變數名 ...
  • 寫在前面 從今天開始的幾篇文章,我將就國內目前比較主流的一些線上學習平臺數據進行抓取,如果時間充足的情況下,會對他們進行一些簡單的分析,好了,平臺大概有 ,`CSDN學院 網易雲課堂 慕課網 mongodb`裡面,如果對上述平臺造成了困擾,請見諒,畢竟我就抓取那麼一小會的時間,不會對伺服器有任何影響 ...
  • Django 系列博客(三) 前言 本篇博客介紹 django 的前後端交互及如何處理 get 請求和 post 請求。 get 請求 get請求是單純的請求一個頁面資源,一般不建議進行賬號信息的傳輸。 配置路由 配置視圖 配置頁面資源 post 請求 配置路由 配置視圖 配置頁面資源 前後端交互 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...