摘要:先說結論,容器真的很好,很輕量級,功能又很重量級。是的版本完成以后,這個的文件系統就是一個標準的的文件系統了,里面的基本工具一應俱全。
容器,目前最火的話題了,在后端的開發中,容器的運用也已經是主流技術了,今天,我們就來說說容器技術,之前我對這一塊的了解不是很多,但是最近有些特殊原因轉成運維工程師了,而公司的全線服務都是docker的,以一個開發人員的習慣,轉成運維以后,還是想對這種東西總想深入了解一下,于是看了不少相關資料并且看了一下docker的源代碼,發現這東西確實很厲害,和之前腦中的docker印象完全不同,于是有了這篇文章。
先說結論,容器真的很好,很輕量級,功能又很重量級。
前言首先,雖然目前docker技術如此火爆,但是其實容器技術本上并不是什么高大上的東西,總的來講,就是對目前的Linux底層的幾個API的封裝,然后圍繞著這幾個API開發出了一套周邊的環境。
之前所有的講關于容器的文章,一開始就開始講UTC隔離,PID隔離,IPC隔離,文件系統隔離,CGroups系統,今天這一篇,我們換一個視角,我們從以下幾個方面來說一下容器技術。
首先,我們從容器和虛擬機說起,都說容器是非常輕量級的,那么和虛擬機比起來,到底輕在什么地方呢。
第二部分,我們會通過一步一步的說明,通過構造一個監獄,來說明如何建立一個簡單的容器,會涉及到容器的各種技術,當然還有一些沒有涉及到的,我認為不影響理解。
第三部分,我們會通過代碼實戰一把,看看如何一步一步按照第二部分的說明啟動一個容器并運行自己的代碼,這一部分的全部代碼都在github上。
最后,我會再說一下docker技術,因為docker從代碼來看,容器技術只是他的一小部分,完整的docker遠比單純的容器要復雜,我會簡單的說一下我對docker的理解,包括docker使用的其他技術點。
容器和虛擬機要說容器,跑不了和虛擬機進行比較,虛擬機是比較古老的技術了,虛擬機的架構圖如下所示。
虛擬機核心是什么?是模擬硬件,讓虛擬機的操作系統以為自己跑在一個真實的物理機器上,用軟件模擬出來CPU,內存,硬盤,網卡,讓虛擬機里面的操作系統覺得自己是在操作真實的硬件,所以虛擬機里面的CPU啊,內存啊都是假的,都是軟件模擬出來的(現在有硬件虛擬化技術了,比純軟件模擬要高級一些,但操作系統不管這些),既然操作系統都騙過去了,當然跑在操作系統上的進程同樣也騙過去了唄,所以這些進程都完全感知不到底層硬件的區別,還以為自己很歡樂的跑在一臺真實的物理機上了。
那么容器又是什么鬼呢?容器的架構圖如下(這張圖網上找的,侵權馬上刪)
和虛擬機一個很明顯的區別就是容器其實并沒有模擬硬件,還是那個硬件,還是那個操作系統,只不過是在操作系統上做了一點文章【這張圖中就是docker engine了】,讓進程以為自己運行在了一個全新的操作系統上,有一個很形象的詞來描述他就是軟禁!就是把進程軟禁在一個環境中,讓進程覺得自己很happy,其實一切盡在操作系統的掌控之中,其實虛擬機也是,虛擬機是把操作系統軟禁起來了,讓操作系統覺得很happy,容器是把進程軟禁起來,你看,一個是軟禁操作系統,一個是軟禁進程,這兩個明顯不是一個級別的東西,誰輕誰重不用說了吧。
既然容器和虛擬機的區別在于一個是通過模擬硬件來軟禁操作系統,一個是通過做做操作系統的手腳來軟禁進程,那么他們能達到的效果也是不一樣的。
對于虛擬機來說,既然是模擬的硬件,那么就可以在windows上裝linux虛擬機了,因為反正是模擬硬件嘛,虛擬機內部的操作系統也不知道外面的宿主機是什么系統。
容器就不一樣了,因為是在操作系統上做文章,所以不可能在linux上裝windows了,并且還有一點就是,容器內的操作系統其實就是外面宿主機的操作系統,兩者其實是一個,你在容器內用uname -a看到的內核版本和外面看到的是一樣的。本質上容器就是一個進程,他和宿主機上任何其他進程沒什么本質的區別。
建造容器監獄如何來做一個容器呢?或者說容器是怎么實現的呢?我們從幾個方面來說一下容器的實現,一是最小系統,二是網絡系統,三是進程隔離技術,四是資源分配。最小系統告訴你軟禁進程所需要的那個舒適的監獄環境,網絡系統告訴你軟禁的進程如何和外界交互,進程隔離技術告訴你如果把進程關到這個舒適的監獄中去,資源分配告訴你監獄里的進程如何給他分配資源讓他不能胡來。
建設基本監獄【最小系統打造】要軟禁一個進程,當然需要有個監獄了,在說監獄之前,我們先看看操作系統的結構,一個完整的操作系統【Linux/Unix操作系統】分成三部分,如下圖所示【本圖也是網上找的,侵權馬上刪,這個圖是四個部分,包括一個boot參數部分,這不是重點】。
首先是bootloader,這部分啟動部分是匯編代碼,CPU從一個固定位置讀取第一行匯編代碼開始運行,bootloader先會初始化CPU,內存,網卡(如果需要),然后這部分的主要作用是把操作系統的kernel代碼從硬盤加載到內存中,然后bootloader使命完成了,跳轉到kernel的main函數入口開始執行kernel代碼,kernel就是我們熟悉的linux的內核代碼了,大家說的看內核代碼就是看的這個部分了,kernel代碼啟動以后,會重新初始化CPU,內存,網卡等設備,然后開始運行內核代碼,最后,啟動上帝進程(init),開始正常運行kernel,然后kernel會掛載文件系統。
好了,到這里,對進程來說都是無意義的,因為進程不關心這些,進程產生的時候這些工作已經做完了,進程能看到的就是這個文件系統了,對進程來說,內存空間,CPU核心數,網絡資源,文件系統是他唯一能看得見使用得到的東西,所以我們的監獄環境就是這么幾項核心的東西了。
kernel和文件系統是可以分離的,比如我們熟悉的ubuntu操作系統,可能用的是3.18的Linux Kernel,再加上一個自己的文件系統,也可以用2.6的Kernel加上同樣的操作系統。每個Linux的發行版都是這樣的,底層的Kernel可能都是同一個,不同的只是文件系統不同,所以,可以簡單的認為,linux的各種發行版就是kernel內核加上一個獨特的文件系統,這個文件系統上有各種各樣的工具軟件。
既然是這樣,那么我們要軟禁一個進程,最基礎的當然要給他一個文件系統啦,文件系統簡單的說就是一堆文件夾加上一堆文件組成的,我們先來生成一個文件系統,我之前是做嵌入式的,嵌入式的Linux系統生成文件系統一般用busybox,只需要在在ubuntu上執行下面的命令,就能生成一個文件系統
apt-get install busybox-static
mkdir rootfs;cd rootfs
mkdir dev etc lib usr var proc tmp home root mnt sys
/bin/busybox --install -s bin
大概這么幾步就制作完成了一個文件系統,也就是監獄的基本環境已經有了,記得把lib文件夾的內容拷過去。制作完了以后,文件系統就這樣了。
還有一種方式,就是使用debootstap這個工具來做,也是幾行命令就做完了一個debian的文件系統了,里面連apt-get都有,docker的基礎文件系統也是這個。
apt-get install qemu-user-static debootstrap binfmt-support
mkdir rootfs
debootstrap --foreign wheezy rootfs //wheezy是debian的版本
cp /usr/bin/qemu-arm-static rootfs/usr/bin/
完成以后,這個wheezy的文件系統就是一個標準的debian的文件系統了,里面的基本工具一應俱全。
OK,基本的監獄環境已經搭建好了,進程住進去以后就跟在外面一樣,啥都能干,但就是跑不出來。
要測試這個環境,可以使用linux的chroot命令,chroot ./rootfs就進入了這個制作好的文件系統了,你可以試試,看不到外面的東西了哦。
打造探視系統【網絡系統】剛剛只建立了一個基本的監獄環境,對于現代的監獄,只有個房子不能上網怎么行?所以對于監獄環境,還需要建立一個網絡環境,好讓里面的進程們可以很方便的和監獄外的親友們聯系啊,不然誰愿意一個人呆在里面啊。
如何來建立一個網絡呢?對于容器而言,很多地方是可配置的,這里說可配置,其實意思就是可配置也可以不配置,對于網絡就是這樣,一般的容器技術,對網絡的支持有以下幾個方式。
無網絡模式,就是不配置模式了,不給他網絡,只有文件系統,適合單機版的程序。
直接和宿主機使用同一套網絡,也是不配置模式,但是這個不配置是不進行網絡隔離,直接使用宿主機的網卡,ip,協議棧,這是最奔放的模式,各個容器如果啟動的是同一套程序,那么需要配置不同的端口了,比如有3個容器,都是redis程序,那么需要啟動三個各不同的端口來提供服務,這樣各個容器沒有做到完全的隔離,但是這也有個好處,就是網絡的吞吐量比較高,不用進行轉發之類的操作。
網橋模式,也是docker默認使用的模式,我們安裝完docker以后會多一個docker0的網卡,其實這是一個網橋,一個網橋有兩個端口,兩個端口是兩個不同的網絡,可以對接兩塊網卡,從A網卡進去的數據會從B網卡出來,就像黑洞和白洞一樣,我們建立好網橋以后,在容器內建一塊虛擬網卡,把他和網橋對接,在容器外的宿主機上也建立一塊虛擬網卡,和網橋對接,這樣容器里面的進程就可以通過網橋這個探視系統和監獄外聯系了。
我們可以直接使用第二種不配置模式,直接使用宿主機的網絡,這也是最容易最方便的,但是我們在這里說的時候稍微說一下第三種的網橋模式吧。
網橋最開始的作用主要是用來連接兩個不同的局域網的,更具體的應用,一般是用來連接兩個不同的mac層的局域網的,比如有線電視網和以太網,一般網橋只做數據的過濾和轉發,也可以適當的做一些限流的工作,沒有路由器那么復雜,實現起來也比較簡單,對高層協議透明,他能操作的都是mac報文,也就是在ip層以下的報文。
對于容器而言,使用網橋的方式是在宿主機上使用brctl命令建立一個網橋,作為容器和外界交互的渠道,也就是大家使用docker的時候,用ifconfig命令看到的docker0網卡,這實際上就是一個網橋,然后每啟動一個容器,就用brctl命令建立一對虛擬網卡,一塊給容器,一塊連到網橋上。這樣操作下來,容器中發給虛擬網卡的數據都會發給網橋,而網橋是宿主機上的,是能連接外網的,所以這樣來做到了容器內的進程能訪問外網。
容器的網絡我沒有深入研究,感覺不是特別復雜,最復雜的方式就是網橋的方式了,這些網絡配置都可以通過命令行來進行,但是docker的源碼中是自己通過系統調用實現的,說實話我沒怎么看明白,功力還是不夠啊。
我使用的就是最最簡單的不隔離,和宿主機共用網卡,只能通過端口來區分不同容器中的服務。
好了,監獄已經建好了,探視系統也有了,得抓人了來軟禁了,把進程抓進來吧。我們以一個最最基本的進程/bin/bash為例,把這個進程抓進監獄吧。
說到抓進程,這時候就需要來聊聊容器的底層技術了,Linux提供幾項基礎技術來進行輕量級的系統隔離,這些個隔離技術組成了我們熟悉的docker的基礎。本篇不會大段的描述這些技術,文章后面我會給出一些參考鏈接,因為這類文章到處都可以找到,本篇只是讓大家對容器本身有個了解。
下面所說的所有基礎技術,其實就是一條系統調用,包括docker的基礎技術,也是這么一條系統調用(當然,docker還有很多其他的,但是就容器來說,這條是核心的了)
clone(進程函數, 進程棧空間, CLONE_NEWUTS | CLONE_NEWPID | CLONE_NEWNS | CLONE_NEWNET |CLONE_NEWUSER | CLONE_NEWIPC , NULL)
這是一條C語言的clone系統調用,實際上就是啟動一個新的進程,后面的參數就是各種隔離了,包括UTS隔離,PID隔離,文件系統隔離,網絡隔離,用戶隔離,IPC通訊隔離。
在go語言中,沒有clone這個系統調用(不知道為什么不做這個系統調用,可能是為了多平臺的兼容吧),必須使用exec.Cmd這個對象來啟動進程,在linux環境下,可以設置Cmd的attr屬性,其中有個屬性叫CloneFlags,可以把上面那些個隔離信息設置進去,這樣,啟動的進程就是我們需要的了,我們可以這么來啟動這個進程
cmd := exec.Command("./container", args...) cmd.SysProcAttr = &syscall.SysProcAttr{ Cloneflags: syscall.CLONE_NEWUTS | syscall.CLONE_NEWPID | syscall.CLONE_NEWNS | syscall.CLONE_NEWNET, } cmd.Run()
這樣,通過這個cmd命令啟動的./container進程就是一個隔離進程了,也就是我們把這個進程給關起來了,他已經看不到其他東西了,是不是很簡單?但是你要是就直接這么運行,還是看不到什么特別的地方。
在這個之后,我們需要按照上面所說的,把監獄先建立好,監獄的建立在./container中進行,建立監獄也比較簡單,基本上也是一堆系統調用,比如文件系統的軟禁,就像下面的一樣
syscall.Mount(rootfs, tmpMountPoint, "", syscall.MS_BIND, "") //掛載根文件系統 syscall.Mount(rootfs+"/proc", tmpMountPoint+"/proc", "proc", 0, ""); //掛載proc文件夾 syscall.PivotRoot(tmpMountPoint, pivotDir) //把進程軟禁到根文件系統中
關于上面proc文件夾,做了特殊處理,在Linux中,proc文件夾的地位比較特殊,具體作用可以自行查文檔,簡單的說就是保存系統信息的文件夾。在這里,dev和sys這兩個特殊文件夾也需要做特殊處理的,這里沒有寫出來而已。
這些都做完了以后,就可以啟動真正需要執行的進程了,比如/bin/bash,或者你自己的程序,這樣啟動的/bin/bash或者你自己的程序就是在監獄中啟動的了,那么他看到的所有東西都是監獄中的了,外面宿主機的一切對他來說都是屏蔽的了,這樣,一個docker的雛形就產生了。
這里多說一下,通過clone系統調用啟動的進程,它自己看到自己的PID是1,也就是上帝進程了,這個上帝進程可以來造基礎監獄【文件系統】,打造放風系統【網絡系統】,然后再通過它來生成新的進程,這些進程出來就在監獄中了,我們使用docker的時候,自己的服務實際上就是這些個在監獄中出生的進程【可能我的描述不太正確啊,我沒有仔細看docker的源碼,我自己感覺是這樣的】。
至此,我們來總結一下,啟動一個最簡單的容器并運行你自己的進程,需要幾步。
建立一個監獄【文件系統】,使用busybox或者debootstrap建立。
建立一個放風系統【網絡系統】,使用網橋或者不隔離網絡,直接使用宿主機的網卡。
抓一個皮卡丘【啟動上帝進程】并放到監獄中【掛載文件系統,初始化網絡】,配置Cloneflags的值,并通過exec.Cmd來進行上帝進程的啟動
讓皮卡丘生個孩子【啟動你自己的程序】,直接調用exec.Cmd的run方法啟動你自己的進程
完成
通過上面幾步,最簡容器就完成了,是不是很簡單?但是容器僅僅有這些是不夠的,我們還有三個隔離沒有講,這里稍微提一下吧。
一個是UTS隔離,主要是用來隔離hostname和域名的。
一個是User隔離,這樣容器里面的用戶和宿主機用戶可以做映射,意思就是里面雖然看到的是root用戶,但是實際上并不是root,不能夠瞎搞系統,這樣容器的安全性會有保障。
一個是IPC隔離,這個是進程通訊的隔離,這樣容器里面的進程和容器外面的進程就不能進行進程間通訊了,保證了比較強的隔離性。
給犯人分配食物【資源配置】我們知道,一般的監獄中的食物是定量的,畢竟不是每個監獄都可以吃自助餐的,容器也一樣,要是我們就啟個容器啥都不限制,里面要是有個牛逼的程序員寫的牛逼程序,瞬間就把你的內存和CPU給干沒了。比如像下面這個fork炸彈。【下面程序請不要嘗試!!】
int main(){ while(fork()); }
在容器技術中,Cgroups【control groups】就是干這個事情的,cgroups負責給監獄設定資源,比如能用幾個cpu啊,cpu能給你多少百分比的使用量啊,內存能用多少啊,磁盤能用多少啊,磁盤的速度能給你多少啊,各種資源都可以從cgroups來進行配置,把這些東西配置給容器以后,就算容器里面運行一個fork炸彈也不怕了,反正影響不到外面的宿主機,到這里,容器已經越來越像虛擬機了。
cgroups是linux內核提供的API,雖然是API,但它的整個實現完美滿足了Linux兩大設計哲學之一:一切皆文件(還有一個哲學是通訊全管道),對API的調用實際上是操作文件。
我們以cpu的核心數看看如何來做一個cgroups的資源管理。假設我們的物理機是個8核的CPU,而我們剛剛啟動的容器我只想讓他使用其中的兩個核,很簡單,我們用命令行直接操作sys/fs/cgroups文件夾下的文件來進行。這個配置我們可以在啟動的上帝進程中進行,也可以在容器外部進行,都是直接操作文件。
關于cgroups這個東西很復雜也很強大,其實在容器出來之前,好的運維工程師就已經把這個玩得很溜了。docker也只是把這些個文件操作封裝了一下,變成了docker的啟動和配置參數而已。
親自抓一次進程吧好了,該說的都說了,我們來實戰一把,自己啟一個容器吧,并且啟動以后為了更直觀的看到效果,我們啟動一個ssh服務,打開22332端口,然后外面就可以通過ssh連到容器內部了,這時候你愛干什么干什么了。
制作文件系統文件系統制作我們直接使用debootstrap進行制作,在/root/目錄下建立一個rootfs的文件夾,然后使用debootstrap --foreign wheezy rootfs 制作文件系統,制作完了以后,文件系統就是下面這個樣子
制作初始化腳本初始化腳本就做兩件事情,一是啟動ssh服務,一是啟動一個shell,提前先把/etc/ssh/sshd_config中的端口改成23322。
#!/bin/bash service ssh start /bin/bash
然后把這個腳本放到制作的文件系統的root目錄下,加上執行權限。
啟動上帝進程文件系統制作完成了,啟動腳本也做完了,我們看看我們這個容器的架構,架構很簡單,整個容器分為兩個獨立的進程,兩份獨立的代碼。
一個是主進程【wocker.go】,這個進程本身就是一個http的服務,通過get方法接收參數,參數有rootfs的地址,容器的hostname,需要監禁的進程名稱(這里就是我們的第二個進程【startContainer.go】),然后通過exec.Cmd這個包啟動這個進程。
第二個進程啟動就是以隔離方式啟動的了,就是容器的上帝進程了,這個進程中進行文件系統掛載,hostname設置,權限系統的設定,然后啟動正式的服務進程(也就是我們的啟動腳本/root/start_container.sh)
掛載文件系統第二個進程是容器的上帝進程,在這里進行文件系統的掛載,最重要的代碼如下
syscall.Mount(rootfs, tmpMountPoint, "", syscall.MS_BIND, "") //掛載根文件系統 syscall.Mount(procpath, tmpMountPointProc, "proc", 0, "") //掛載proc文件夾,用來看系統信息的 syscall.Mount(syspath, tmpMountPointSys, "sysfs", 0, "") //掛載sys文件夾,用來做權限控制的 syscall.Mount("udev", tmpMountPointDev, "devtmpfs", 0, "") //掛載dev,用來使用設備的 syscall.PivotRoot(tmpMountPoint, pivotDir)//進入到文件系統中
具體代碼可以看github上的文件,這樣,根文件系統就掛載完了,已經進入了基本監獄中了。
啟動初始化腳本文件系統掛載完了以后,然后啟動初始化腳本,這個就比較簡單了,一個exec.Cmd的Run方法調用就搞定了。
cmd := exec.Command("/root/start_container.sh")
這樣,ssh服務就在容器中啟動了,可以看到一行Starting OpenBSD Secure Shell server: sshd.的打印信息,容器啟動完成,這時候,我們可以通過ssh root@127.0.0.1 -p 23322這個命令登錄進我們的容器了,然后你就可以為所欲為了。
上面那個圖,我們看到登錄進來以后,hostname已經顯示為我們設定的hello了,這時這個會話已經在容器里面了,我們ps一下看看進程們。
看到pid為1的進程了么,那個就是啟動這個容器的上帝進程了。恩,到這里,我們已經在容器中了,這里啟動的任何東西都和我們知道的docker中的進程沒什么太大區別了。
但在這里,我缺失了權限的部分,大家可以自己加上去,主要是各種文件操作比較麻煩。。。
關于Docker的思考docker這門最近兩年非常火的技術,光從容器的角度來看的話,也不算什么新的牛逼技術了,和虛擬機比起來還是要簡單不少,當然,docker本身可完全不止容器技術本身,還有AUFS文件分層技術,還有etcd集群技術,最關鍵的是docker通過自己的整個生態把容器包裹在里面了,提供了一整套的容器管理套件,這樣讓容器的使用變得異常簡單,所以docker才能這么流行吧。
和虛擬機比起來,docker的優點實在是太多了。
首先,從易用性的角度來說,管理一個虛擬機的集群,有一整套軟件系統,比如openstack這種,光熟悉這個openstack就夠喝一壺的了,而且openstack的網絡管理異常復雜,哦,不對,是{{BANNED}}級的復雜,要把網絡調通不是那么容易的事情。
第二,從性能上來看看,我們剛剛說了容器的原理,所以實際上容器不管是對CPU的利用,還是內存的操作或者外部設備的操作,對一切硬件的操作實際上都是直接操作的,并沒有經過一個中間層進行過度,但是虛擬機就不一樣了,虛擬機是先操作假的硬件,然后假硬件再操作真硬件,利用率從理論上就會比容器的要差,雖然現在有硬件虛擬化的技術了能提升一部分性能,但從理論上來說性能還是沒有容器好,這部分我沒有實際測試過啊,只是從理論上這么覺得的,如果有不對的歡迎拍磚啊。
第三,從部署的易用性上和啟動時間上,容器就完全可以秒了虛擬機了,這個不用多說吧,一個是啟動一臺假電腦,一個是啟動一個進程。
那么,docker和虛擬機比起來,缺點在哪里呢?
我自己想了半天,除了資源隔離性沒有虛擬機好以外,我實在是想不出還有什么缺點,因為cgroups的隔離技術只能設定一個上限,比如在一臺4核4G的機器上,你可能啟動兩個docker,給他們的資源都是4核4G,如果有個docker跑偏了,一個人就干掉了4G內存,那么另外一個docker可能申請不到資源了。而虛擬機就不存在這個問題,但是這也是個雙刃劍,docker的這種做法可以更多的榨干系統資源,而虛擬機的做法很可能在浪費系統資源。
除了這個,我實在是想不出還有其他缺點。網上也有說權限管理沒有虛擬機好,但我覺得權限這東西,還是得靠人,靠軟件永遠靠不住。
最后,代碼都在github上,只有非常非常簡單的三個文件【一個Container.go是容器類,一個wocker.go沒內容,一個startContainer.go啟動容器】,那個http服務留著沒寫,后面寫http服務的時候在用一下。
恩,docker確實是個好東西。
如果你覺得不錯,歡迎轉發給更多人看到,也歡迎關注我的公眾號,主要聊聊搜索,推薦,廣告技術,還有瞎扯。。文章會在這里首先發出來:)掃描或者搜索微信號XJJ267或者搜索西加加語言就行
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/26669.html
摘要:此刻的后手指依舊飛速地敲打鍵盤,絲毫沒有要停不下來意思。閱讀本期技術周刊,你不光能弄明白什么是,使用的意義何在,還將被傳授秘籍,以達的境界。周刊篩選的每篇內容,是作者的獨到見解,踩坑總結和經驗分享。 showImg(https://segmentfault.com/img/bVC5qJ?w=900&h=385); 啪嗒啪嗒,啪嗒啪嗒,聽到后排動感十足的清脆鍵盤響,我就能猜到公司程序員定...
摘要:這個實際上給出了通過集合代數發展出來的關系型數據庫怎么進行數據操作和檢索的。 本篇趟個雷,把數據庫納入到輪子中了,前面說到了數據庫其實不算輪子,也說到了其實我寫不出來數據庫,這里所說的數據庫嚴格來說是關系型數據庫,他比輪子復雜多了,是一個和操作系統差不多復雜度的東西,所以才能通過一個oralce養活一家全球50強的公司,其次,數據庫太復雜了,要寫出來實在是力所不能及,但是后來有想了一下...
摘要:前端技術棧還是非常龐大的,為了能夠借助已經存在的輪子來造出一輛車,所以我選擇了進行實踐。狀態的管理的狀態管理依靠完成,用其來管理的所有組件狀態。私有云客戶端打造主頁面首先是主頁面,可以打開任何一個云主機系統的頁面看,基本類似。 showImg(https://segmentfault.com/img/remote/1460000013930354); 【利用K8S技術棧打造個人私有...
摘要:前端技術棧還是非常龐大的,為了能夠借助已經存在的輪子來造出一輛車,所以我選擇了進行實踐。狀態的管理的狀態管理依靠完成,用其來管理的所有組件狀態。私有云客戶端打造主頁面首先是主頁面,可以打開任何一個云主機系統的頁面看,基本類似。 showImg(https://segmentfault.com/img/remote/1460000013930354); 【利用K8S技術棧打造個人私有...
閱讀 1804·2023-04-26 02:14
閱讀 3727·2021-11-23 09:51
閱讀 1385·2021-10-13 09:39
閱讀 3971·2021-09-24 10:36
閱讀 3012·2021-09-22 15:55
閱讀 3518·2019-08-30 12:57
閱讀 2039·2019-08-29 15:30
閱讀 1986·2019-08-29 13:19