Docker 與 Kubernetes在前端開發的應用

Docker是開發人員和系統管理員使用容器開發、部署和運行應用程序的平臺,使用Linux容器來部署應用程序稱爲集裝箱化,使用Docker能夠輕鬆部署應用程序。Docker 和傳統部署方式最大的不一樣在於,它將不會限制咱們使用任何工具,任何語言,任何版本的 runtime,Docker 將咱們的應用當作一個只提供網絡服務的盒子(也即容器),Kubernetes 則是對這些盒子進行更多自動化的操做,自動建立,自動重啓,自動擴容,自動調度,這個過程稱之爲容器編排。javascript

如今,容器編排技術給 Web 應用帶來了巨大的靈活性,讓咱們輕鬆建立須要的程序對外提供服務。和傳統的 IaaS 相比,不須要去關心雲主機申請,雲主機配置等信息,也不需考慮雲主機故障致使的服務不可用,由 Kubernetes 的副本控制器幫咱們完成雲主機故障發生後容器遷移。下面就讓咱們來看一下Docker和Kubernetes在前端應用開發的一些應用。html

Docker安裝

和前端工具同樣,使用Docker容器以前,須要先安裝對應的工具。
Linux Debian/Ubuntu, 安裝 社區版DockerCE
Windows 一鍵安裝
macOS 一鍵安裝前端

須要說明的是,Windows7 系統,須要使用 VirtualBox 安裝 Linux 做爲 Docker 的宿主機,Windows10 Pro 會使用 Hyper-V 安裝 Linux 做爲 Docker 的宿主機。java

咱們可使用阿里雲的鏡像進行下載,而後再進行安裝。node

http://mirrors.aliyun.com/docker-toolbox/mac/docker-for-mac/

安裝完成後,啓動Docker便可。linux

配置鏡像加速

在國內訪問默認的官方鏡像比較慢,咱們可使用阿里雲的鏡像加速,註冊阿里帳號並申請容器服務以後,而後點擊容器鏡像服務的鏡像加速地址查看地址,以下圖所示。
在這裏插入圖片描述
而後在Docker的Preferences中配置中添加加速地址,選擇Resources的Proxies填入阿里雲的鏡像加速地址,以下所示。
在這裏插入圖片描述nginx

註冊Docker ID

w爲了方便使用和管理鏡像,咱們能夠點擊Docker官方地址來註冊Docker ID。註冊完成以後,就能夠在Mac版Docker桌面工具中進行登陸,並查看本身已有的鏡像,以下圖所示。
在這裏插入圖片描述git

基本使用

Docker命令

打開終端,而後輸入命令docker便可查看Docker支持的命令,以下所示。github

Usage:    docker [OPTIONS] COMMAND
 
A self-sufficient runtime for containers
 
Options:
      --config string      Location of client config files (default "/Users/crane/.docker")
  -c, --context string     Name of the context to use to connect to the daemon (overrides DOCKER_HOST env var and default context set with "docker context use")
  -D, --debug              Enable debug mode
  -H, --host list          Daemon socket(s) to connect to
  -l, --log-level string   Set the logging level ("debug"|"info"|"warn"|"error"|"fatal") (default "info")
      --tls                Use TLS; implied by --tlsverify
      --tlscacert string   Trust certs signed only by this CA (default "/Users/crane/.docker/ca.pem")
      --tlscert string     Path to TLS certificate file (default "/Users/crane/.docker/cert.pem")
      --tlskey string      Path to TLS key file (default "/Users/crane/.docker/key.pem")
      --tlsverify          Use TLS and verify the remote
  -v, --version            Print version information and quit
 
Management Commands:
  app*        Docker Application (Docker Inc., v0.8.0)
  builder     Manage builds
  buildx*     Build with BuildKit (Docker Inc., v0.3.1-tp-docker)
  checkpoint  Manage checkpoints
  config      Manage Docker configs
  container   Manage containers
  context     Manage contexts
  image       Manage images
  manifest    Manage Docker image manifests and manifest lists
  network     Manage networks
  node        Manage Swarm nodes
  plugin      Manage plugins
  secret      Manage Docker secrets
  service     Manage services
  stack       Manage Docker stacks
  swarm       Manage Swarm
  system      Manage Docker
  trust       Manage trust on Docker images
  volume      Manage volumes
 
Commands:
  attach      Attach local standard input, output, and error streams to a running container
  build       Build an image from a Dockerfile
  commit      Create a new image from a container's changes
  cp          Copy files/folders between a container and the local filesystem
  create      Create a new container
  deploy      Deploy a new stack or update an existing stack
  diff        Inspect changes to files or directories on a container's filesystem
  events      Get real time events from the server
  exec        Run a command in a running container
  export      Export a container's filesystem as a tar archive
  history     Show the history of an image
  images      List images
  import      Import the contents from a tarball to create a filesystem image
  info        Display system-wide information
  inspect     Return low-level information on Docker objects
  kill        Kill one or more running containers
  load        Load an image from a tar archive or STDIN
  login       Log in to a Docker registry
  logout      Log out from a Docker registry
  logs        Fetch the logs of a container
  pause       Pause all processes within one or more containers
  port        List port mappings or a specific mapping for the container
  ps          List containers
  pull        Pull an image or a repository from a registry
  push        Push an image or a repository to a registry
  rename      Rename a container
  restart     Restart one or more containers
  rm          Remove one or more containers
  rmi         Remove one or more images
  run         Run a command in a new container
  save        Save one or more images to a tar archive (streamed to STDOUT by default)
  search      Search the Docker Hub for images
  start       Start one or more stopped containers
  stats       Display a live stream of container(s) resource usage statistics
  stop        Stop one or more running containers
  tag         Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE
  top         Display the running processes of a container
  unpause     Unpause all processes within one or more containers
  update      Update configuration of one or more containers
  version     Show the Docker version information
  wait        Block until one or more containers stop, then print their exit codes
Run 'docker COMMAND --help' for more information on a command.

關於這些命令的含義,能夠看Docker 經常使用命令web

好比,咱們要搜索nginx鏡像,那麼只須要使用下面的命令便可。

docker search nginx

搜索結果中標記【OFFICIAL】的爲官方鏡像,其餘爲用戶自定義鏡像,可根據實際須要選擇。
在這裏插入圖片描述
若是要獲取鏡像,可使用docker pull命令,以下所示,獲取nginx。

# 拉取指定版本xxx鏡像
docker pull nginx:xxx
# 拉取最新版本鏡像 
docker pull nginx    //等價於docker pull nginx:latest

鏡像拉取成功後,而後使用下面的命令啓動nginx容器,以下所示。

docker run -d -p 8080:80 --name docker-nginx nginx

上面的命令會將容器內部的80端口映射到了本機的8080端口,因此啓動成功後可使用http://localhost:8080/訪問docker容器內部nginx80端口映射的地址,以下圖所示。
在這裏插入圖片描述
一些常見的啓動參數:

  • -p 本機端口:容器端口 映射本地端口到容器
  • -P 將容器端口映射爲本機隨機端口
  • -v 本地路徑或卷名:容器路徑 將本地路徑或者數據卷掛載到容器的指定位置
  • -it 做爲交互式命令啓動
  • -d 將容器放在後臺運行 --rm 容器退出後清除資源

查看及中止容器

查看容器的基本命令以下所示。

# 查看運行中的容器
docker ps
 
# 查看全部容器(包括正在運行和已經中止運行的)
docker ps -a

中止容器命令使用的是kill命令,以下所示。

# 經過id直接關閉容器
# docker kill a0fbf4519279
# 經過容器名稱直接關閉容器
docker kill docker-nginx
 
# 經過id直接容器 默認等待十秒 超時強制關閉
# docker stop a0fbf4519279
# 經過容器名稱關閉容器 默認等待十秒 超時強制關閉  等價於 docker stop -t=10 docker-nginx
docker stop docker-nginx

從新啓動容器的命令以下。

# 啓動容器可經過容器id或者容器名稱
# 經過容器名稱啓動容器,若是已啓動則忽略
docker start docker-nginx
 
# 經過容器名稱從新啓動容器,若是未啓動則直接啓動,若是已啓動則關閉再啓動
# docker restart docker-nginx

Docker是如何工做的

Docker 使用的是 C/S 結構,即客戶端/服務器體系結構。明白了 Docker 客戶端與 Docker 服務器進行交互時, Docker 服務端負責構建、運行和分發 Docker 鏡像。 而且Docker 客戶端和服務端能夠運行在一臺機器上,能夠經過 RESTful 、 stock 或網絡接口與遠程 Docker 服務端進行通訊。

而Docker 的底層核心原理是利用了 Linux 內核的 namespace 以及 cgroup 特性,其中 namespace 進行資源隔離,cgroup 進行資源配額, 其中 Linux 內核中一共有 6 種 namespace,分別對應以下。

在這裏插入圖片描述
在系統調用中有三個與namespace有關的函數,分別是clone、unshare和setns。

clone:若是想讓子進程擁有獨立的網絡地址,TCP/IP 協議棧,那麼就可使用clone,以下所示。參考:https://man7.org/linux/man-pages/man2/clone.2.html

clone(cb, *stack , CLONE_NEWNET, 0)

unshare:將當前進程轉移到新的 namespace 中, 例如使用 fork 或 vfork 建立的進程將默認共享父級資源,使用 unshare 將子進程從父級取消共享。參考:https://man7.org/linux/man-pages/man2/setns.2.html

setns:給指定的PID指定 namespace, 一般用於共享 namespace。參考:https://man7.org/linux/man-pages/man2/setns.2.html

Linux 的內核層支持了在系統調用中隔離 namespace, 經過給一個進程分配單獨的 namespace 從而讓其在各個資源維度進行隔離,每一個進程都能獲取到本身的主機名,IPC、 PID、IP和根文件系統、用戶組等信息,就像在一個獨佔系統中,不過雖然資源進行了隔離,可是內核仍是共享同一個,這也是比傳統虛擬機輕量的緣由之一。

另外只有資源進行隔離還不夠,要想保證真正的故障隔離,互不影響, 還須要對針對 CPU, 內存,GPU 等進行限制,由於若是一個程序出現死循環或者內存泄露也會致使別的程序沒法運行。

Docker 網絡

一個容器要想提供服務,就須要將自身的網絡暴露出去。Docker 是與宿主機上的環境是隔離的,要想暴露服務就須要顯示告訴 Docker 哪些端口容許外部訪問,在運行 docker run -p 80:80 nginx 時這裏就是將容器內部的 80 端口暴露到宿主機的 80 端口上,具體的端口轉發下面會具體分析一下。容器的網絡部分是容器中最重要的部分,也是構建大型集羣的基石,在咱們部署 Docker 的應用時,須要要對網絡有個基本的瞭解。

目前,Docker 提供了四種網絡模式,分別爲 Host、Container、 None和Bridge ,咱們可使用 --net 來進行指定網絡模式。

Host 模式

Host 模式不會單獨爲容器建立 network namespace, 容器內部直接使用宿主機網卡,此時容器內獲取 ip 爲宿主機 ip,端口綁定直接綁在宿主機網卡上,優勢是網絡傳輸時不用通過 NAT 轉換,效率更高速度更快。可是docker host上已經使用的端口就不能再用了,網絡的隔離性很差。

可使用以下的命令開啓Host模式。

docker run --net host nginx

Host模式的示意圖以下所示。
在這裏插入圖片描述

Container 模式

和指定的 container 共享 network namespace, 共享網絡配置,ip 地址和端口,其中沒法共享網絡模式爲 Host 的容器。新建立的容器不會建立本身的網卡,配置本身的 IP,而是和一個指定的容器共享 IP、端口範圍等。一樣,兩個容器除了網絡方面,其餘的如文件系統、進程列表等仍是隔離的,兩個容器的進程能夠經過 lo 網卡設備通訊。

開啓Host模式的命令以下。

docker run --net container:xxx_containerid nginx

None 模式

使用none模式,Docker容器擁有本身的Network Namespace,可是,並不爲Docker容器進行任何網絡配置。也就是說,這個Docker容器沒有網卡、IP、路由等信息。須要咱們本身爲Docker容器添加網卡、配置IP等。指定爲 None 模式的容器內將不會分配網卡設備,僅有內部 lo 網絡。
在這裏插入圖片描述
啓動None 模式的命令以下所示。

docker run --net none busybox ifconfig

Bridge 模式

該模式爲默認模式,容器啓動時會被分配一個單獨的 network namespace,同時 Docker 在安裝/初始化時會在宿主機上建立一個名爲 docker0 的網橋,該網橋也做爲容器的默認網關,容器網絡會在該網關網段內進行 ip 的分配。

Bridge 模式的啓動命令以下所示。

docekr run --net bridge busybox ifconfig

Bridge模式的示意圖下圖所示。
在這裏插入圖片描述
而且,當咱們執行 docker run -p 3000:80 nginx 命令時,Docker 會在宿主機上建立下面一條 iptable 轉發規則。
在這裏插入圖片描述

在上圖中,當外部請求主機網卡 3000 端口時將它進行目的地址轉換(DNAT), 目的地址修改成 172.18.0.2,端口修改成 80,修改好目的地址後流量會從本機默認網卡通過 docker0 轉發到對應的容器,這樣當外部請求宿主機的 3000 端口,內部會將流量轉發給內部容器服務,從而實現服務的暴露,流程示意圖以下所示。
在這裏插入圖片描述

一樣 Docker 內部訪問外部接口也會進行源地址轉換(SNAT), 容器內部請求 google.com, 服務器上收到的則是主機網卡的 ip。

Bridge 模式因爲多了一層 NAT 轉換因此效率會比 Host 模式差一些,可是可以很好的隔離外部網絡環境,讓容器獨享 ip 且具備完整的端口空間。

上面四種網絡模式是 Docker 自帶的幾種工做方式,可是部署 Kubernetes 須要全部的容器都工做在一個局域網中,因此在部署集羣時須要多主機網絡插件的支持。

Flannel

多主機網絡解決方案有 CNCF 推出的 CNI 規範以及 Docker 自帶的 CNM 方案,可是目前你們用的最多的仍是 CNI 規範,其中一種實現就是 Flannel。

Flannel 使用了報文嵌套技術來解決多主機網絡互通問題,將原始報文進行封包,指定包ip爲目的主機地址,等包到達主機後再進行拆包傳送到對應的容器。Flannel是 CoreOS 團隊針對 Kubernetes 設計的一個覆蓋網絡(Overlay Network)工具,其目的在於幫助每個使用 Kuberentes 的 CoreOS 主機擁有一個完整的子網。下圖顯示 flannel 使用效率更高的 UDP 協議來在主機間傳輸報文。

在這裏插入圖片描述
對上圖,咱們簡單的說明下:

  1. 數據從源容器中發出後,經由所在主機的docker0虛擬網卡轉發到flannel0虛擬網卡,這是個P2P的虛擬網卡,flanneld服務監聽在網卡的另一端。
  2. Flannel經過Etcd服務維護了一張節點間的路由表,該張表裏保存了各個節點主機的子網網段信息。
  3. 源主機的flanneld服務將本來的數據內容UDP封裝後根據本身的路由表投遞給目的節點的flanneld服務,數據到達之後被解包,而後直接進入目的節點的flannel0虛擬網卡,而後被轉發到目的主機的docker0虛擬網卡,最後就像本機容器通訊同樣的由docker0路由到達目標容器。

目前主流跨主機通訊目前經常使用的有三種,分別是Overlay、hostgw和BGP技術。

  • overlay: 即上面的報文嵌套。

hostgw: 經過修改主機路由表實現轉發,不須要拆包和封包,效率更高,但一樣限制比較多,只適合在相同局域網中的主機使用。
BGP:使用軟件實現的 BGP(邊界網關協議)以此向網絡中的路由器廣播路由規則。和 hostgw 同樣不須要拆包,可是實現成本較高。

Kubernetes

在小規模場景下,使用 Docker 能夠一鍵部署應用確實很方便,可是當出現須要在幾百臺主機上進行多副本部署,須要管理這麼多主機的運行狀態以及服務的故障時須要在其餘主機重啓服務,想象一下就知道手動的方式不是一種可取的方案,這時候就須要利用 Kubernetes 這種更高維度的編排工具來管理了。

Kubernetes 簡稱 K8S,是Google 2014年建立管理的大規模容器管理技術。 簡單說 K8S 就是抽象了硬件資源,將 N 臺物理機或雲主機抽象成一個資源池,容器的調度交給 K8S 進行管理,CPU 不夠用就調度到一臺足夠使用的機器上,內存不知足要求就會尋找一臺有足夠內存的機器在上面建立對應的容器,服務由於某些緣由掛了, K8S 還會幫咱們自動遷移重啓。K8S是一個開源的平臺,實現了容器集羣的自動化部署、自動擴縮容、維護等功能。

Kubernetes 具備以下特色:

  • 可移植: 支持公有云,私有云,混合雲,多重雲(multi-cloud)。
  • 可擴展: 模塊化, 插件化, 可掛載, 可組合。
  • 自動化: 自動部署,自動重啓,自動複製,自動伸縮/擴展。

Kubernetes架構

K8s集羣由兩節點組成:Master和Node。在Master上運行etcd,Api Server,Controller Manager和Scheduler四個組件。後三個組件構成了K8s的總控中心,負責對集羣中全部資源進行管控和調度。在每一個Node上運行kubect、proxy和docker daemon三個組件,負責對節點上的Pod的生命週期進行管理,以及實現服務代理的功能。另外全部節點上均可以運行kubectl命令行工具。

API Server做爲集羣的核心,負責集羣各功能模塊之間的通訊。集羣內的功能模塊經過Api Server將信息存入到etcd,其餘模塊經過Api Server讀取這些信息,從而實現模塊之間的信息交互。Node節點上的Kubelet每隔一個時間週期,經過Api Server報告自身狀態,Api Server接收到這些信息後,將節點信息保存到etcd中。Controller Manager中 的Node controller經過Api server按期讀取這些節點狀態信息,並作響應處理。Scheduler監聽到某個Pod建立的信息後,檢索全部符合該pod要求的節點列表,並將pod綁定到節點列表中最符合要求的節點上。若是scheduler監聽到某個Pod被刪除,則調用api server刪除該Pod資源對象。kubelet監聽pod信息,若是監聽到pod對象被刪除,則刪除本節點上的相應的pod實例,若是監聽到修改Pod信息,則會相應地修改本節點的Pod實例。

Kubernetes主要由如下幾個核心組件組成:

  • etcd保存了整個集羣的狀態;
  • apiserver提供了資源操做的惟一入口,並提供認證、受權、訪問控制、API註冊和發現等機制;
  • controller manager負責維護集羣的狀態,好比故障檢測、自動擴展、滾動更新等;
  • scheduler負責資源的調度,按照預約的調度策略將Pod調度到相應的機器上;
  • kubelet負責本Node節點上的Pod的建立、修改、監控、刪除等生命週期管理,同時Kubelet定時「上報」本Node的狀態信息到Api Server裏;
  • Container runtime負責鏡像管理以及Pod和容器的真正運行(CRI);

Kubernetes安裝

在Mac中安裝了Docker以後,會自動安裝了Kubernetes,正常狀況下,咱們只須要在Docker的Preferrences->Kubernetes中勾選Enable Kubernetes,而後點擊Apply按鈕便可。
在這裏插入圖片描述
可是因爲【牆】的問題,若是您是直接在Docker中啓用Kubernetes,Kubernetes的狀態會一直都是kubernetes is starting...,緣由是有一些Kubernetes依賴的鏡像不能正常的下載。
在這裏插入圖片描述
Github上有個開源項目能夠幫咱們手動拉取鏡像,執行下面命令拉去改項目代碼到本地。

https://github.com/xiangzhihong/k8s-docker-desktop-for-mac
cd k8s-docker-desktop-for-mac
sh load_images.sh

而後,執行下面的命令驗證是否安裝成功。

kubectl cluster-info
K8S 與傳統 IaaS 系統的不一樣

IaaS 就是 Infrastructure as a service, 所謂基礎設施即服務,開發者想要上線一個新應用須要申請主機,ip, 域名等一系列資源,而後登陸主機自行搭建所需環境,部署應用上線,這樣不只不利於大規模操做,並且還增長了出錯的可能,運維或開發這經常本身寫腳本自動化完成,遇到一些差別再手動修改腳本,很是痛苦。

K8S 則是將基礎設施可編程化,由原來的人工申請改成一個清單文件自動建立,開發者只須要提交一份文件,K8S 將會自動爲你分配建立所需的資源。對這些設施的 CRUD 均可以經過程序的方式自動化操做。

爲了瞭解 K8S 的基礎知識,下面來部署一個 Node SSR 應用。首先,初始化一個應用模版。

npm install create-next-app
npx create-next-app next-app
cd next-app

建立好工程後給添加一個 Dockerfile 用來構建服務的鏡像Dockerfile。

FROM node:8.16.1-slim as build

COPY ./ /app

WORKDIR /app
RUN npm install
RUN npm run build
RUN rm -rf .git


FROM node:8.16.1-slim

COPY --from=build /app /

EXPOSE 3000
WORKDIR /app

CMD ["npm", "start"]

Dockerfile 作了兩部分優化:

  • 使用精簡版的 node 基礎鏡像, 大大減小鏡像體積
  • 使用分步構建的方式, 可以減小鏡像層數以及移除臨時文件從而減小了鏡像體積。

而後使用下面的命令構建鏡像。

docker build  . --tag next-app

以後咱們就能夠向 Kubernetes 提出咱們應用的要求了。爲了保證高可用,服務至少建立兩個副本,咱們還須要一個應用的域名當這個域名請求到咱們集羣上時自動轉發到咱們的服務上。那麼咱們對應的配置文件Deployment.yaml就能夠這麼寫。

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: app-ingress
spec:
  rules:
  - host: next-app-server
    http:
      paths:
      - backend:
          serviceName: app-service
          servicePort: 80

---
kind: Service
apiVersion: v1
metadata:
  name: app-service
spec:
  selector:
    app: web
  ports:
  - port: 80
    targetPort: 3000

---

apiVersion: apps/v1
kind: Deployment
metadata:
  name: app-deployment
spec:
  replicas: 2
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      containers:
      - image: next-app
        name: next-app
          imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 3000

上面清單主要的功能是:

  • 首先須要一個 Deployment 控制器,鏡像爲 next-app, 服務端口爲 3000,給我建立兩個副本。
  • 還須要建立一個 Service, 這個 Service 指向由副本控制器建立的幾個 next-app。
  • 申請一個 Ingress 入口, 域名爲 next-app-server, 其指向剛剛的 Service。

而後,執行下面的命令提交申請給 K8S。

kubectl apply -f ./Deployment.yaml

接着就能夠看到已經部署的 pod。

sh-4.4$ kubectl get pod
NAME                              READY     STATUS    RESTARTS   AGE
app-deployment-594c48dbdb-4f4cg   1/1       Running   0          1m
app-deployment-594c48dbdb-snj54   1/1       Running   0          1m

而後瀏覽器打開 Ingress 裏配置的域名便可訪問對應的應用(前提是這個域名可以打到你的 K8S 集羣節點上),以下圖所示。
在這裏插入圖片描述

應用發佈系統

K8S 僅僅負責容器的編排,實際上若是部署應用還須要外部 Pipeline 的支持,代碼的構建,靜態檢查,鏡像的打包由 Pipeline 完成。
在這裏插入圖片描述目前,國內用的比較多的發佈系統經常由下面幾個服務組成:GitLab/GitHub、Jenkins,、Sonar,、Harbor等。

相關文章
相關標籤/搜索