Kubernetes 在知名互聯(lián)網(wǎng)公司的落地實(shí)踐_第1頁(yè)
Kubernetes 在知名互聯(lián)網(wǎng)公司的落地實(shí)踐_第2頁(yè)
Kubernetes 在知名互聯(lián)網(wǎng)公司的落地實(shí)踐_第3頁(yè)
Kubernetes 在知名互聯(lián)網(wǎng)公司的落地實(shí)踐_第4頁(yè)
免費(fèi)預(yù)覽已結(jié)束,剩余7頁(yè)可下載查看

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

1、 Kubernetes 在知名互聯(lián)網(wǎng)公司的落地實(shí)踐 容器化背景本來(lái)生活網(wǎng)()是一家生鮮電商平臺(tái),公司很早就停止了燒錢(qián)模式,開(kāi)始追求盈利。既然要把利潤(rùn)最大化,那就要開(kāi)源節(jié)流,作為技術(shù)可以在省錢(qián)的方面想想辦法。我們的生產(chǎn)環(huán)境是由 IDC 機(jī)房的 100 多臺(tái)物理機(jī)所組成,占用率高達(dá) 95%,閑置資源比較多,于是我們考慮借助 k8s 來(lái)重構(gòu)我們的基礎(chǔ)設(shè)施,提高我們資源的利用率。容器化項(xiàng)目團(tuán)隊(duì)最初加上我就只有三個(gè)人,同時(shí)我們還有各自的工作任務(wù)要做,留給容器化的時(shí)間較少,因此我們要考慮如何快速的搭建容器平臺(tái),避免走全部自研這條路,這對(duì)我們來(lái)說(shuō)是個(gè)巨大的挑戰(zhàn)。在經(jīng)歷了一年的容器化之旅后,分享下我們這一年所

2、踩過(guò)的坑和獲得的經(jīng)驗(yàn)。面臨的問(wèn)題在搭建 k8s 集群前,有很多問(wèn)題擺在我們面前:l人手不足,時(shí)間也不充裕,不能有太多自研的需求l我們目前的發(fā)布是由測(cè)試人員完成的,不可能要求他們?nèi)?xiě)一個(gè) yaml 或執(zhí)行 kubectl 做發(fā)布,這個(gè)學(xué)習(xí)成本太高也容易出錯(cuò),因此我們必須構(gòu)建一個(gè)用戶體驗(yàn)良好的可視化平臺(tái)給發(fā)布人員使用l我們有大量的 .NET 項(xiàng)目,而 .NET 環(huán)境又依賴 WindowslConfigMap/Secret 不支持版本控制,同時(shí)用來(lái)存業(yè)務(wù)配置也不是很方便lk8s 集群和外部的通信如何打通容器平臺(tái)作為小團(tuán)隊(duì)去構(gòu)建一個(gè)容器平臺(tái),自研的工作量太大了。前期我們調(diào)研過(guò)很多可視化平臺(tái),比如 k8

3、sdashboard 和 rancher 等等,但是要操作這些平臺(tái)得需要專業(yè)的 k8s 運(yùn)維知識(shí),這對(duì)我們的測(cè)試人員不太友好。后來(lái)我們嘗試了 KubeSphere(kubesphere.io)平臺(tái),各方面都比較符合我們的需求,于是決定使用該平臺(tái)作為我們?nèi)萜髌脚_(tái)的基礎(chǔ),在這之上構(gòu)建我們自己的發(fā)布流程。感興趣的朋友可以去了解下這個(gè)平臺(tái)。.NET 項(xiàng)目我們的項(xiàng)目有 Java 也有 .NET 的,.NET 項(xiàng)目占了 80% 以上。要支持.NET 意味著要支持 Windows。在我們?nèi)ツ觊_(kāi)始啟動(dòng)項(xiàng)目的時(shí)候,k8s 剛升級(jí)到 1.14 版本,是支持Windows 節(jié)點(diǎn)的第一個(gè)版本,同時(shí)功能也比較弱。經(jīng)過(guò)實(shí)

4、驗(yàn),我們成功對(duì) .NET Framework 的程序進(jìn)行了容器化,在不改代碼的前提下運(yùn)行在了 Windows 服務(wù)器上,并通過(guò) k8s 進(jìn)行管理。不過(guò)我們也遇到了一些比較難處理的問(wèn)題,使用下來(lái)的總結(jié)如下:lKubernetes 版本必須是 1.14 版本或以上l大多數(shù) Linux 容器若不做處理會(huì)自動(dòng)調(diào)度到 Windows 節(jié)點(diǎn)上lWindows 基礎(chǔ)鏡像體積普遍比較大l必須使用 Windows Server 2019 及以上版本lk8s 關(guān)鍵性組件以 Windows 服務(wù)形式運(yùn)行,而非 Podl存儲(chǔ)和網(wǎng)絡(luò)的支持有局限性l部署步驟復(fù)雜,易出錯(cuò)我們調(diào)研了一段時(shí)間后決定放棄使用 Linux 和Wi

5、ndows 的混合集群,因?yàn)檫@些問(wèn)題會(huì)帶來(lái)巨大的運(yùn)維成本,而且也無(wú)法避免 Windows 的版權(quán)費(fèi)。我們也考慮過(guò)把這些項(xiàng)目轉(zhuǎn)換成 Java,但其中包含大量的業(yè)務(wù)邏輯代碼,把這些重構(gòu)為 Java 會(huì)消耗巨大的研發(fā)和測(cè)試的人力成本,顯然這對(duì)我們來(lái)說(shuō)也是不現(xiàn)實(shí)的。那么有沒(méi)有一種方案是改動(dòng)很少的代碼,卻又能支持 Linux 的呢?答案很明顯了,就是把 .NET 轉(zhuǎn) .NET Core。我們采用了這種方案,并且大多數(shù)情況能很順利的轉(zhuǎn)換一個(gè)項(xiàng)目而不需要修改一行業(yè)務(wù)邏輯代碼。當(dāng)然這個(gè)方案也有它的局限性,比如遇到如下情況就需要修改代碼無(wú)法直接轉(zhuǎn)換:l項(xiàng)目里使用了依賴 Windows API 的代碼l引用的第三

6、方庫(kù)無(wú) .NET Core 版本lWCF 和 Web Forms 的代碼這些修改的成本是可控的,也是我們可以接受的。到目前為止我們已經(jīng)成功轉(zhuǎn)換了許多 .NET 項(xiàng)目,并且已運(yùn)行在 k8s 生產(chǎn)環(huán)境之上。集群暴露由于我們是基于物理機(jī)部署也就是裸金屬(Bare Metal)環(huán)境,所以無(wú)論基于什么平臺(tái)搭建,最終還是要考慮如何暴露 k8s 集群這個(gè)問(wèn)題。暴露方式lLoadBalancer, 是 Kubernetes 官方推薦的暴露方式,很可惜官方支持的方式都需要部署在云上。我們公司全部是裸機(jī)環(huán)境部署,無(wú)法使用云方案。lNodePort,端口范圍一般是 30000 以上,每個(gè)端口只能對(duì)應(yīng)一種服務(wù)。如果應(yīng)

7、用越來(lái)越多,那端口可能就不夠用了。它最大的問(wèn)題是如果你暴露某一個(gè)節(jié)點(diǎn)給外部訪問(wèn),那么這個(gè)節(jié)點(diǎn)會(huì)成為單點(diǎn)。如果你要做高可用,這幾個(gè)節(jié)點(diǎn)都暴露出去,前面一樣也要加一個(gè)負(fù)載均衡,這樣事情就復(fù)雜了。lIngress,可以解決 NodePort 端口復(fù)用的問(wèn)題,它一般工作在7層上可以復(fù)用 80 和 443 端口。使用 Ingress 的前提是必須要有 Ingress Controller 配合,而 Ingress Controller 同樣會(huì)出現(xiàn)你需要暴露端口并公開(kāi)的問(wèn)題。這時(shí)候如果你用 HostNetwork 或 HostPort 把端口暴露在當(dāng)前的節(jié)點(diǎn)上,就存在單點(diǎn)問(wèn)題;如果你是暴露多個(gè)節(jié)點(diǎn)的話,同

8、樣需要在前面再加一個(gè)LB。lHostNetwork/HostPort,這是更暴力的方式,直接把 Pod 的端口綁定到宿主機(jī)的端口上。這時(shí)候端口沖突會(huì)是一個(gè)很大的問(wèn)題,同時(shí)單點(diǎn)問(wèn)題依舊存在。裸金屬方案我們分別試用了兩套方案 MetalLB(metallb.universe.tf)和 Porter(/kubesphere/porter),這兩個(gè)都是以 LoadBalancer 方式暴露集群的。我們測(cè)試下來(lái)都能滿足需求。Porter 是 KubeSphere 的子項(xiàng)目,和 KubeSphere 平臺(tái)兼容性更好,但是目前 Porter 沒(méi)有如何部署高可用的文檔,我在這里簡(jiǎn)單分享下:前置條件l首先你的路

9、由器,必須是三層交換機(jī),需要支持 BGP 協(xié)議?,F(xiàn)在大多數(shù)路由設(shè)備都會(huì)支持這個(gè)協(xié)議,所以這個(gè)條件一般都能滿足l其次集群節(jié)點(diǎn)上不能有建立 BGP 通信的其他服務(wù)。舉例來(lái)說(shuō),當(dāng)使用 Calico 時(shí),開(kāi)啟了BGP模式。它的 BGP 端口運(yùn)行在每個(gè)集群節(jié)點(diǎn),Calico 和 Porter 同時(shí)啟用BGP 協(xié)議,會(huì)有部分節(jié)點(diǎn)同時(shí)運(yùn)行兩個(gè)組件與交換機(jī)建立 BGP 協(xié)議造成沖突。而 KubeSphere 默認(rèn)安裝的 Calico 是 ipip 模式的,所以我們沒(méi)有遇到?jīng)_突問(wèn)題l最后一定要有網(wǎng)絡(luò)運(yùn)維人員支持,配合你完成路由器配置以及了解整個(gè)網(wǎng)絡(luò)拓?fù)浣Y(jié)構(gòu)。了解網(wǎng)絡(luò)拓?fù)浣Y(jié)構(gòu)是非常重要的,否則會(huì)遇到很多問(wèn)題配置和

10、部署架構(gòu)和邏輯Porter有兩個(gè)插件:Porter-Manager 和 Porter-AgentPorter-Manager 是使用Deployment 部署到 Master 節(jié)點(diǎn)上的,但默認(rèn)只部署1個(gè)副本,它負(fù)責(zé)同步 BGP 路由到物理交換機(jī)(單向 BGP 路由,只需將 kubernetes 私有路由發(fā)布給交換機(jī)即可,無(wú)需學(xué)習(xí)交換機(jī)內(nèi)物理網(wǎng)絡(luò)路由)。還有一個(gè)組件,Porter-Agent,它以 DaemonSet 的形式在所有節(jié)點(diǎn)都部署一個(gè)副本,功能是維護(hù)引流規(guī)則。高可用架構(gòu)部署好后,你可能會(huì)有疑問(wèn):l單個(gè)路由器掛了怎么辦l單個(gè) porter-manager 掛了怎么辦lporter-man

11、ager 和路由器網(wǎng)絡(luò)斷了怎么辦lEIP 下一跳地址所在的節(jié)點(diǎn)掛了怎么辦l某個(gè) EIP 流量突然飆升,一個(gè)節(jié)點(diǎn)扛不住怎么辦一般路由器或交換機(jī)都會(huì)準(zhǔn)備兩臺(tái)做 VSU (Virtual Switching Unit) 實(shí)現(xiàn)高可用,這個(gè)是網(wǎng)絡(luò)運(yùn)維擅長(zhǎng)的,這里不細(xì)講了。主要說(shuō)下其他幾點(diǎn)怎么解決l確保一個(gè) EIP 有多條 BGP 路由規(guī)則,交換機(jī)和 Manager 是多對(duì)多部署的l確保交換機(jī)開(kāi)啟等價(jià)路由(ECMP)l要做好故障演練和壓力測(cè)試MetalLB 的高可用部署也是類似思路,雖然架構(gòu)稍有不同,比如它和路由器進(jìn)行 BGP 通信的組件是 Speaker,對(duì)應(yīng) Porter 的 Manager;它與Po

12、rter 的區(qū)別在于高可用目前做的比較好;但是 Local 引流規(guī)劃不如 Porter,EIP 的下一跳節(jié)點(diǎn)必須是 BGP 對(duì)等體(鄰居)。配置中心Kubernetes 的 ConfigMap 和 Secret 在一定程度上解決了配置的問(wèn)題,我們可以很輕松的使用它們進(jìn)行更改配置而不需要重新生成鏡像,但我們?cè)谑褂玫倪^(guò)程中還是會(huì)遇到一些痛點(diǎn):1.不支持版本控制Deployment 和 StatefulSet 都有版本控制,我們可以使用 rollout 把應(yīng)用回滾到老的版本,但是 ConfigMap/Secret 卻沒(méi)有版本控制,這會(huì)產(chǎn)生一個(gè)問(wèn)題就是當(dāng)我們的Deployment 要進(jìn)行回滾時(shí),使用的

13、 ConfigMap 還是最新的,我們必須把 ConfigMap 改回上一個(gè) Deployment 版本所使用的 ConfigMap 內(nèi)容,再進(jìn)行回滾,但是這樣的操作是很危險(xiǎn)的,假設(shè)改完 ConfigMap 后有個(gè) Pod 出了問(wèn)題自動(dòng)重啟了,又或者 ConfigMap 以文件形式掛載到 Pod 中,都會(huì)造成程序讀取到了錯(cuò)誤的配置。一個(gè)折中的做法是每個(gè)版本都關(guān)聯(lián)一個(gè)單獨(dú)的 ConfigMap。2.不太適合管理業(yè)務(wù)配置一個(gè)應(yīng)用有時(shí)候會(huì)需要加很多業(yè)務(wù)配置,在維護(hù)大量業(yè)務(wù)配置時(shí),我們可能需要搜索關(guān)鍵字、查看某個(gè) key 的備注、對(duì) value 的格式進(jìn)行校驗(yàn)、批量更新配置等等,但是如果使用了Conf

14、igMap ,我們就不得不再做一些工具來(lái)滿足這些需求,而這些需求對(duì)于配置的維護(hù)效率是有非常大的影響。3.熱更新我們知道如果 ConfigMap 是以文件形式進(jìn)行掛載,那么當(dāng)修改了 ConfigMap 的值后,過(guò)一會(huì)所有的 Pod 里相應(yīng)的文件都會(huì)變更,可是如果是以環(huán)境變量的方式掛載卻不會(huì)更新。為了讓我們的程序支持熱更新,我們需要把 ConfigMap 都掛載成文件,而當(dāng)配置有很多時(shí)麻煩就來(lái)了,如果 Key 和文件是一對(duì)一掛載,那么 Pod 里會(huì)有很多小文件;如果所有 Key 都放到一個(gè)文件里,那么維護(hù)配置就成了噩夢(mèng)。4.配置大小限制ConfigMap 本身沒(méi)有大小限制,但是 etcd 有,默認(rèn)

15、情況下一個(gè) ConfigMap 限制為 1MB,我們估算了下,有個(gè)別應(yīng)用的配置加起來(lái)真有可能突破這個(gè)限制,為了繞過(guò)這個(gè)大小限制,目前也只有切割成多個(gè) ConfigMap 的方法了。為了解決這些痛點(diǎn),我們綜合考慮了很多方案,最終決定還是使用一套開(kāi)源的配置中心作為配置的源,先通過(guò)Jenkins 把配置的源轉(zhuǎn)換成 ConfigMap,以文件形式掛載到 Pod 中進(jìn)行發(fā)布,這樣以上的問(wèn)題都可以迎刃而解。我們選擇了攜程的 Apollo(/ctripcorp/apollo)作為配置中心 ,其在用戶體驗(yàn)方面還是比較出色的,能滿足我們?nèi)粘>S護(hù)配置的需求。微服務(wù)在遷移微服務(wù)到 k8s 集群的時(shí)候基本都會(huì)遇到一個(gè)

16、問(wèn)題,服務(wù)注冊(cè)的時(shí)候會(huì)注冊(cè)成 Pod IP,在集群內(nèi)的話沒(méi)有問(wèn)題,在集群外的服務(wù)可就訪問(wèn)不到了。我們首先考慮了是否要將集群外部與 Pod IP 打通,因?yàn)檫@樣不需要修改任何代碼就能很平滑的把服務(wù)遷移過(guò)來(lái),但弊端是這個(gè)一旦放開(kāi),未來(lái)是很難收回來(lái)的,并且集群內(nèi)部的 IP 全部可訪問(wèn)的話,等于破壞了 k8s 的網(wǎng)絡(luò)設(shè)計(jì),思考再三覺(jué)得這不是一個(gè)好的方法。我們最后選擇了結(jié)合集群暴露的方式,把一個(gè)微服務(wù)對(duì)應(yīng)的 Service 設(shè)置成 LoadBalancer,這樣得到的一個(gè) EIP 作為服務(wù)注冊(cè)后的 IP,手動(dòng)注冊(cè)的服務(wù)只需要加上這個(gè) IP 即可,如果是自動(dòng)注冊(cè)的話就需要修改相關(guān)的代碼。這個(gè)方案有個(gè)小小的

17、問(wèn)題,因?yàn)橐粋€(gè)微服務(wù)會(huì)有多個(gè) Pod,而在遷移的灰度過(guò)程中,外部集群也有這個(gè)微服務(wù)的實(shí)例在跑,這時(shí)候服務(wù)調(diào)用的權(quán)重會(huì)不均衡,因?yàn)榧簝?nèi)的微服務(wù)只有一個(gè) IP,通常會(huì)被看作是一個(gè)實(shí)例。因此如果你的業(yè)務(wù)對(duì)負(fù)載均衡比較敏感,那你需要修改這里的邏輯。調(diào)用鏈監(jiān)控我們一直使用的是點(diǎn)評(píng)的 CAT(/dianping/cat)作為我們的調(diào)用鏈監(jiān)控,但是要把 CAT 部署到 k8s 上比較困難,官方也無(wú)相關(guān)文檔支持??偨Y(jié)部署 CAT 的難點(diǎn)主要有以下幾個(gè):lCAT 每個(gè)實(shí)例都是有狀態(tài)的,并且根據(jù)功能不同,相應(yīng)的配置也會(huì)不同,因此每個(gè)實(shí)例的配置是需要不一樣的,不能簡(jiǎn)單的掛載 ConfigMap 來(lái)解決lCAT 每

18、個(gè)實(shí)例需要綁定一個(gè) IP 給客戶端使用,不能使用 Service 做負(fù)載均衡。lCAT 每個(gè)實(shí)例必須事先知道所有實(shí)例的 IP 地址lCAT 每個(gè)實(shí)例會(huì)在代碼層面獲取自己的 IP,這時(shí)候獲取到的是可變的 Pod IP,與綁定的 IP 不一致,這就會(huì)導(dǎo)致集群內(nèi)部通信出問(wèn)題為了把 CAT 部署成一個(gè) StatefulSet 并且支持?jǐn)U容,我們參考了 Kafka 的 Helm 部署方式,做了以下的工作:l我們?yōu)槊總€(gè) Pod 創(chuàng)建了一個(gè) Service,并且啟用 LoadBalancer 模式綁定了 IP,使每個(gè) Pod 都會(huì)有一個(gè)獨(dú)立的對(duì)外 IP 地址,稱它為 EIP;l我們把所有實(shí)例的信息都保存在配

19、置中心,并且為每個(gè)實(shí)例生成了不同的配置,比如有些實(shí)例是跑 Job,有些實(shí)例是跑監(jiān)控的;l我們會(huì)預(yù)先規(guī)劃好 EIP,并把這些 EIP 列表通過(guò)動(dòng)態(tài)生成配置的方式傳給每個(gè)實(shí)例;l最后我們給每個(gè)實(shí)例里塞了一個(gè)特殊的文件,這個(gè)文件里存的是當(dāng)前這個(gè)實(shí)例所綁定的 EIP 地址。接著我們修改了 CAT 的代碼,把所有獲取本地 IP 地址的代碼改成了讀取這個(gè)特定文件里的 IP 地址,以此欺騙每個(gè)實(shí)例認(rèn)為這個(gè) EIP 就是它自己的本地 IP。擴(kuò)容很簡(jiǎn)單,只需要在配置中心里添加一條實(shí)例信息,重新部署即可。CI/CD由于 KubeSphere 平臺(tái)集成了 Jenkins,因此我們基于 Jenkins 做了很多 CI

20、/CD 的工作。發(fā)布流程起初我們?yōu)槊總€(gè)應(yīng)用都寫(xiě)了一個(gè) Jenkinsfile,里面的邏輯有拉取代碼、編譯應(yīng)用、上傳鏡像到倉(cāng)庫(kù)和發(fā)布到 k8s 集群等。接著我為了結(jié)合現(xiàn)有的發(fā)布流程,通過(guò) Jenkins 的動(dòng)態(tài)參數(shù)實(shí)現(xiàn)了完全發(fā)布、制作鏡像、發(fā)布配置、上線應(yīng)用、回滾應(yīng)用這樣五種流程。處理配置由于前面提到了 ConfigMap 不支持版本控制,因此配置中心拉取配置生成 ConfigMap 的事情就由 Jenkins 來(lái)實(shí)現(xiàn)了。我們會(huì)在 ConfigMap 名稱后加上當(dāng)前應(yīng)用的版本號(hào),將該版本的 ConfigMap 關(guān)聯(lián)到 Deployment 中。這樣在執(zhí)行回滾應(yīng)用時(shí) ConfigMap 也可以一起

21、回滾。同時(shí) ConfigMap 的清理工作也可以在這里完成。復(fù)用代碼隨著應(yīng)用的增多,Jenkinsfile 也越來(lái)越多,如果要修改一個(gè)部署邏輯將會(huì)修改全部的 Jenkinsfile,這顯然是不可接受的,于是我們開(kāi)始優(yōu)化 Jenkinsfile。首先我們?yōu)椴煌愋偷膽?yīng)用創(chuàng)建了不同的 yaml 模板,并用模板變量替換了里面的參數(shù)。接著我們使用了 Jenkins Shared Library 來(lái)編寫(xiě)通用的 CI/CD 邏輯,而 Jenkinsfile 里只需要填寫(xiě)需要執(zhí)行什么邏輯和相應(yīng)的參數(shù)即可。這樣當(dāng)一個(gè)邏輯需要變更時(shí),我們直接修改通用庫(kù)里的代碼就全部生效了。數(shù)據(jù)落地隨著越來(lái)越多的應(yīng)用接入到容器發(fā)布中,不可避免的要對(duì)這些應(yīng)用的發(fā)布及部署上線的發(fā)布效率、失敗率、發(fā)布次數(shù)等指標(biāo)進(jìn)行分析;其次我們當(dāng)前的流程雖然實(shí)現(xiàn)了 CI/CD 的流程代碼復(fù)用,但是很多參數(shù)還是要去改對(duì)應(yīng)應(yīng)用的 Jenkinsfile 進(jìn)行調(diào)整,這也很不方便。于是我們決定將所有應(yīng)用的基本信息、發(fā)布信息

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論