成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

一篇文章帶你深入剖析Docker鏡像

開源
本文主要從Docker鏡像的概念說起,然后結合一些實際的場景進行對比分析闡述更深層次的實現過程,有助于幫助大家理解Docker鏡像。

[[429016]]

作者:喬克

公眾號:運維開發故事

知乎:喬克叔叔

大家好,我是喬克,一名一線運維實踐者。

鏡像對于YAML工程師來說都不陌生,每天都在和他打交道,編寫、構建、發布,重復而有趣。

在我們編寫一個構建鏡像的Dockerfile之后,只要應用能正常跑起來,便很少再去看這個Dockerfile了(至少我是這樣)。對于這個Dockerfile是不是想象中的那么合理,是不是還可以再優化一下,并沒有做太深入的思考。

本文主要從以下幾個方面帶你深入了解鏡像的知識。

鏡像的基本概念

在了解一件事物的時候,腦海中總是會先問一句“是什么”,學習Docker鏡像也是同樣的道理,什么是Docker鏡像?

在說Docker鏡像之前,先簡單說說Linux文件系統。

典型的Linux文件系統由bootfs和rootfs組成,bootfs會在Kernel加載到內存后umount掉,所以我們進入系統看到的都是rootfs,比如/etc,/prod,/bin等標準目錄。

我們可以把Docker鏡像當成一個rootfs,這樣就能比較形象是知道什么是Docker鏡像,比如官方的ubuntu:21.10,就包含一套完整的ubuntu:21.10最小系統的rootfs,當然其內是不包含內核的。

Docker鏡像是一個_特殊的文件系統_,它提供容器運行時需要的程序、庫、資源、配置還有一個運行時參數,其最終目的就是能在容器中運行我們的代碼。

以上是從宏觀的的視角去看Docker鏡像是什么,下面再從微觀的角度來深入了解一下Docker鏡像。假如我們現在只有一個ubuntu:21.10鏡像,如果現在需要一個nginx鏡像,是不是可以直接在這個鏡像中安裝一個nginx,然后這個鏡像是不是就可以變成nginx鏡像?

答案是可以的。其實這里面就有一個分層的概念,底層用的是ubuntu鏡像,然后在上面疊加了一個nginx鏡像,這樣就完成了一個nginx鏡像的構建了,這種情況我們稱ubuntu鏡像為nginx的父鏡像。

這么說起來還是有點不好理解,介紹完下面的鏡像存儲方式,就好理解了。

鏡像的存儲方式

在說鏡像的存儲方式之前,先簡單介紹一個UnionFS(聯合文件系統,Union File System)。

所謂UnionFS就是把不同物理位置的目錄合并mount到同一個目錄中,然后形成一個虛擬的文件系統。一個最典型的應用就是將一張CD/DVD和一個硬盤的目錄聯合mount在一起,然后用戶就可以對這個只讀的CD/DVD進行修改了。

Docker就是充分利用UnionFS技術,將鏡像設計成分層存儲,現在使用的就是OverlayFS文件系統,它是眾多UnionFS中的一種。

OverlayFS只有lower和upper兩層。顧名思義,upper層在上面,lower層在下面,upper層的優先級高于lower層。

在使用mount掛載overlay文件系統的時候,遵守以下規則。

  • lower和upper兩個目錄存在同名文件時,lower的文件將會被隱藏,用戶只能看到upper的文件。
  • lower低優先級的同目錄同名文件將會被隱藏。
  • 如果存在同名目錄,那么lower和upper目錄中的內容將會合并。
  • 當用戶修改merge中來自upper的數據時,數據將直接寫入upper中原來目錄中,刪除文件也同理。
  • 當用戶修改merge中來自lower的數據時,lower中內容均不會發生任何改變。因為lower是只讀的,用戶想修改來自lower數據時,overlayfs會首先拷貝一份lower中文件副本到upper中。后續修改或刪除將會在upper下的副本中進行,lower中原文件將會被隱藏。
  • 如果某一個目錄單純來自lower或者lower和upper合并,默認無法進行rename系統調用。但是可以通過mv重命名。如果要支持rename,需要CONFIG_OVERLAY_FS_REDIRECT_DIR。

下面以OverlayFS為例,直面感受一下這種文件系統的效果。

系統:CentOS 7.9 Kernel:3.10.0

(1)創建兩個目錄lower、upper、merge、work四個目錄

  1. # # mkdir lower upper work merge 

其中:

  • lower目錄用于存放lower層文件
  • upper目錄用于存放upper層文件
  • work目錄用于存放臨時或者間接文件
  • merge目錄就是掛載目錄

(2)在lower和upper兩個目錄中都放入一些文件,如下:

  1.  # echo "From lower." > lower/common-file 
  2.  # echo "From upper." > upper/common-file 
  3.  # echo "From lower." > lower/lower-file 
  4.  # echo "From upper." > upper/upper-file 
  5.  # tree  
  6. ├── lower 
  7. │   ├── common-file 
  8. │   └── lower-file 
  9. ├── merge 
  10. ├── upper 
  11. │   ├── common-file 
  12. │   └── upper-file 
  13. └── work 

可以看到lower和upper目錄中有相同名字的文件common-file,但是他們的內容不一樣。

(3)將這兩個目錄進行掛載,命令如下:

  1. # mount -t overlay -o lowerdir=lower,upperdir=upper,workdir=work overlay merge 

掛載的結果如下:

  1. # tree  
  2. ├── lower 
  3. │   ├── common-file 
  4. │   └── lower-file 
  5. ├── merge 
  6. │   ├── common-file 
  7. │   ├── lower-file 
  8. │   └── upper-file 
  9. ├── upper 
  10. │   ├── common-file 
  11. │   └── upper-file 
  12. └── work 
  13.     └── work 
  14. # cat merge/common-file  
  15. From upper

可以看到兩者共同目錄common-dir內容進行了合并,重復文件common-file為uppderdir中的common-file。

(4)在merge目錄中創建一個文件,查看效果

  1. # echo "Add file from merge" > merge/merge-file 
  2. # tree  
  3. ├── lower 
  4. │   ├── common-file 
  5. │   └── lower-file 
  6. ├── merge 
  7. │   ├── common-file 
  8. │   ├── lower-file 
  9. │   ├── merge-file 
  10. │   └── upper-file 
  11. ├── upper 
  12. │   ├── common-file 
  13. │   ├── merge-file 
  14. │   └── upper-file 
  15. └── work 
  16.     └── work 

可以看到lower層沒有變化,新增的文件會新增到upper層。

(5)修改merge層的lower-file,效果如下

  1. # echo "update lower file from merge" > merge/lower-file  
  2. # tree  
  3. ├── lower 
  4. │   ├── common-file 
  5. │   └── lower-file 
  6. ├── merge 
  7. │   ├── common-file 
  8. │   ├── lower-file 
  9. │   ├── merge-file 
  10. │   └── upper-file 
  11. ├── upper 
  12. │   ├── common-file 
  13. │   ├── lower-file 
  14. │   ├── merge-file 
  15. │   └── upper-file 
  16. └── work 
  17.     └── work 
  18.  
  19. # cat upper/lower-file  
  20. update lower file from merge 
  21. # cat lower/lower-file  
  22. From lower

可以看到lower層同樣沒有變化,所有的修改都發生在upper層。

從上面的實驗就可以看到比較有意思的一點:不論上層怎么變,底層都不會變。

Docker鏡像就是存在聯合文件系統的,在構建鏡像的時候,會一層一層的向上疊加,每一層構建完就不會再改變了,后一層上的任何改變都只會發生在自己的這一層,不會影響前面的鏡像層。

我們通過一個例子來進行闡述,如下圖。

具體如下:

  • 基礎L1層有file1和file2兩個文件,這兩個文件都有具體的內容。
  • 到L2層的時候需要修改file2的文件內容并且增加file3文件。在修改file2文件的時候,系統會先判定這個文件在L1層有沒有,從上圖可知L1層是有file2文件,這時候就會把file2復制一份到L2層,然后修改L2層的file2文件,這就是用到了聯合文件系統寫時復制機制,新增文件也是一樣。
  • 到L3層修改file3的時候也會使用寫時復制機制,從L2層拷貝file3到L3層 ,然后進行修改。
  • 然后我們在視圖層看到的file1、file2、file3都是最新的文件。

上面的鏡像層是死的。當我們運行容器的時候,Docker Daemon還會動態生成一個讀寫層,用于修改容器里的文件,如下圖。

比如我們要修改file2,就會使用寫時復制機制將file2復制到讀寫層,然后進行修改。同樣,在容器運行的時候也會有一個視圖,當我們把容器停掉以后,視圖層就沒了,但是讀寫層依然保留,當我們下次再啟動容器的時候,還可以看到上次的修改。

值得一提的是,當我們在刪除某個文件的時候,其實并不是真的刪除,只是將其標記為刪除然后隱藏掉,雖然我們看不到這個文件,實際上這個文件會一直跟隨鏡像。

到此對鏡像的分層存儲有一定的認識了?這種分層存儲還使得鏡像的復用、定制變得更容易,就像文章開頭基于ubuntu定制nginx鏡像。

Dockerfile和鏡像的關系

我們經常在應用代碼里編寫Dockerfile來制作鏡像,那Dockerfile和鏡像到底是什么關系呢?沒有Dockerfile可以制作鏡像嗎?

我們先來看一個簡單的Dockerfile是什么樣的。

  1. FROM ubuntu:latest 
  2. ADD run.sh /   
  3. VOLUME /data   
  4. CMD ["./run.sh"]   

通過這幾個命令就可以做出新的鏡像?

是的,通過這幾個命令組成文件,docker就可以使用它制作出新的鏡像,這是不是有點像給你一些檸檬、冰糖、金銀花就能制作出一杯檸檬茶一個道理?

這個一聯想,Dockerfile和鏡像的關系就清晰明了了。

Dockerfile就是一個原材料,鏡像就是我們想要的產品。當我們想要制作某一個鏡像的時候,配置好Dcokerfile,然后使用docker命令就能輕松的制作出來。

那不用Dockerfile可以制作鏡像嗎?

答案是可以的,這時候就需要我們先啟動一個基礎鏡像,通過docker exec命令進入容器,然后安裝我們需要的軟件,最好再使用docker commit生成新的鏡像即可。這種方式就沒有Dockerfile那么清晰明了,使用起來也比較麻煩。

鏡像和容器的關系

上面說了Dockerfile是鏡像的原材料,在這里,鏡像就是容器的運行基礎。

容器鏡像和我們平時接觸的操心系統鏡像是一個道理,當我們拿到一個操作系統鏡像,比如一個以iso結尾的centos鏡像,正常情況下,這個centos操作系統并不能直接為我們提供服務,需要我們去安裝配置才行。

容器鏡像也是一樣。

當我們通過Dockerfile制作了一個鏡像,這時候的鏡像是靜態的,并不能為我們提供需要的服務,我們需要通過docker將這個鏡像運行起來,使它從鏡像變成容器,從靜態變成動態。

簡單來說,鏡像是文件,容器是進程。容器是通過鏡像創建的,沒有 Docker 鏡像,就不可能有 Docker 容器,這也是 Docker 的設計原則之一。

鏡像的優化技巧

上面介紹了什么是鏡像、鏡像的存儲方式以及Dockerfile和鏡像、鏡像和容器之間關系,這節主要介紹我們在制作鏡像的時候有哪些技巧可以優化鏡像。

Docker鏡像構建通過docker build命令觸發,docker build會根據Dockerfile文件中的指令構建Docker鏡像,最終的Docker鏡像是由Dockerfile中的命令所表示的層疊加起來的,所以從Dockerfile的制作到鏡像的制作這一系列之間都有可以優化和注意的地方。

鏡像優化可以分兩個方向:

  • 優化鏡像體積
  • 優化構建速度

優化鏡像體積

優化鏡像體積主要就是從制作Dockerfile的時候需要考慮的事情。

上面以及介紹過鏡像是分層存儲的,每個鏡像都會有一個父鏡像,新的鏡像都是在父鏡像的基礎之上構建出來的,比如下面的Dockerfile。

  1. FROM ubuntu:latest 
  2. ADD run.sh /   
  3. VOLUME /data   
  4. CMD ["./run.sh"]   

這段Dockerfile的父鏡像是ubuntu:latest,在它的基礎之上添加腳本然后組成新的鏡像。

所以在優化體積方面,可以從以下幾個方面進行考慮。

(1)選擇盡可能小的基礎鏡像

在Docker hub上的同一個基礎鏡像會存在多個版本,如果可以,我建議你使用alpine版本,這個版本的鏡像是經過許多優化,減少了很多不必要的包,節約了體積。這里就以常用的openjdk鏡像為例,簡單看一下它們的大小差別。

首先在Docker hub上可以看到openjdk:17-jdk和openjdk:17-jdk-alpine的鏡像大小,如下:

可以看到同一個版本alpine版本的鏡像比正常的版本小50MB左右,所以用這兩個做基礎鏡像構建出來的鏡像大小也會有差別。

但是是不是所有基礎鏡像都選alpine版本呢?

不是的,alpine鏡像也會有很多坑,比如。

  • 使用alpine版本鏡像容易出錯,因為這個版本鏡像經過了大量的精簡優化,很多依賴庫都沒有,如果程序需要依賴動態鏈接庫就容易報錯,比如Go中的cgo調用。
  • 域名解析行為跟 glibc 有差異,Alpine 鏡像的底層庫是 musl libc,域名解析行為跟標準 glibc 有差異,需要特殊作一些修復配置,并且有部分選項在 resolv.conf 中配置不支持。
  • 運行 bash 腳本不兼容,因為沒有內置 bash,所以運行 bash 的 shell 腳本會不兼容。

所以使用alpine鏡像也需要好好斟酌一下,在實際應用中,如果要使用alpine鏡像,最好在其上做一些初始化,把需要的依賴、庫、命令等先封裝進去制作成新的基礎鏡像,其他應用再以這個基礎鏡像為父鏡像進行操作。

(2)鏡像層數盡量少

上面說過鏡像是分層存儲的,如果上層需要修改下層的文件需要使用寫時復制機制,而且下層的文件依然存在并不會消失,如果層數越多,鏡像的體積相應的也會越大。

比如下面的Dockerfile。

  1. FROM ubuntu:latest 
  2. RUN apt update 
  3. RUN apt install git -y 
  4. RUN apt install curl -y 
  5. ADD run.sh / 
  6. CMD ["./run.sh"

這個Dockerfile能跑起來嗎?完全沒問題,但是這樣寫是不是就會導致鏡像的層數非常多?

拋開父鏡像ubuntu:latest本身的層不說,上面的Dockerfile足足增加了5層。在Dockerfile中是支持命令的合并的,我們可以把上面的Dockerfile改成如下。

  1. FROM ubuntu:latest 
  2. RUN apt update && \ 
  3.     apt install git -y && \ 
  4.     apt install curl -y 
  5. ADD run.sh / 
  6. CMD ["./run.sh"

這樣一改,就把鏡像的層數從5層降低至3層,而且整個邏輯并沒有改變。

說明:在 Docker1.10 后有所改變,只有 RUN、COPY、ADD 指令會創建層,其他指令會創建臨時的中間鏡像,不會直接增加構建的鏡像大小 。

(3)刪除不必要的軟件包

在制作鏡像的時候,腦海中始終要想起一句話:鏡像盡可能的保持精簡。這樣也有助于提高鏡像的移植性。

比如下面的Dockerfile。

  1. FROM ubuntu:latest 
  2. COPY a.tar.gz /opt 
  3. RUN cd /opt && \ 
  4.     tar xf a.tar.gz 
  5. CMD ["./run.sh"

在這個鏡像中,我們從外部拷貝了一個壓縮文件a.tar.gz,在解壓過后我們并沒有把這個原始包刪除掉,它依然會占用著空間,我們可以把這個Dockerfile改成如下。

  1. FROM ubuntu:latest 
  2. COPY a.tar.gz /opt 
  3. RUN cd /opt && \ 
  4.     tar xf a.tar.gz && \ 
  5.     rm -f a.tar.gz 
  6. CMD ["./run.sh"

這樣不僅得到了我們想要的文件,也沒有保留不必要的軟件包。

(4)使用多階段構建

這個不是必須。

為什么這么說呢?因為多階段構建主要是為了解決編譯環境留下的多余文件,使最終的鏡像盡可能小。那為什么說不是必須呢,因為這種情況很多時候都會在做CI的時候給分開,編譯是編譯的步驟,構建是構建的步驟,所以我說不是必須。

但是這種思路是非常好的,可以通過一個Dockerfile將編譯和構建都寫進去,如下。

  1. FROM golang AS build-env 
  2. ADD . /go/src/app 
  3. WORKDIR /go/src/app 
  4. RUN go get -u -v github.com/kardianos/govendor 
  5. RUN govendor sync 
  6. RUN GOOS=linux GOARCH=386 go build -v -o /go/src/app/app-server 
  7.  
  8. FROM alpine 
  9. RUN apk add -U tzdata 
  10. RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai  /etc/localtime 
  11. COPY --from=build-env /go/src/app/app-server /usr/local/bin/app-server 
  12. EXPOSE 8080 
  13. CMD [ "app-server" ] 

其主要是通過在Dockerfile中定義多個FROM基礎鏡像來實現多階段,階段之間可以通過索引或者別名來引用。

優化鏡像體積就總結這4點,如果你有更多更好的方法,歡迎溝通交流。

優化構建速度

當制作好Dockerfile之后,就需要構建鏡像了,很多時候看著構建的速度就著急,那有什么辦法可以優化一下呢?這里從以下幾個方面進行表述。

(1)優化網絡速度

網絡是萬惡之源。比如許多人的基礎鏡像都是直接從docker hub上拉取,如果一臺機器是第一次拉是非常緩慢的,這時候我們可以先把docker hub上的鏡像放到本地私有倉庫,這樣在同一個網絡環境中,拉取速度會比直接到docker hub上拉取快1萬倍。

還有一個鏡像分發技術,比如阿里的dragonfly,充分采用了p2p的思想,提高鏡像的拉取分發速度。

(2)優化上下文

不知道你有沒有注意到,當我們使用docker build構建鏡像的時候,會發送一個上下文給Docker daemon,如下:

  1. # docker build -t test:v1 . 
  2. Sending build context to Docker daemon  11.26kB 
  3. Step 1/2 : FROM ubuntu 
  4. ...... 

原來在使用docker build構建鏡像的時候,會把Dockerfile同級目錄下的所有文件都發送給docker daemon,后續的操作都是在這個上下文中發生。

所以,如果你Dockerfile的同級目錄存在很多不必要的文件,不僅會增加內存開銷,還會拖慢整個構建速度,那有什么辦法進行優化嗎?

這里提供兩種方法:

  • 如果Dockerfile必須放在代碼倉庫的根目錄,這時候可以在這個目錄下添加一個.dockerignore文件,在里面添加需要忽略的文件和文件夾,這樣在發送上下文的時候就不會發送不必要的文件了。
  • 重新創建一個新的目錄放置Dockerfile,保持這個目錄整潔干凈。

(3)充分使用緩存

Docker鏡像是分層存儲的,在使用docker build構建鏡像的時候會默認使用緩存,在構建鏡像的時候,Docker都會先從緩存中去搜索要使用的鏡像,而不是創建新的鏡像,其規則是:從該基本鏡像派生的所有子鏡像,與已在緩存中的鏡像進行比較,以查看是否其中一個是使用完全相同的指令構建的。如果不一樣,則緩存失效,重新構建。

簡單歸納就以下三個要素:

  • 父鏡像沒有變化
  • 構建的指令沒有變化
  • 添加的文件沒有變化

只要滿足這三個要素就會使用到緩存,加快構建速度。

上面從體積和效率上分別介紹了Docker鏡像的優化和注意事項,如果嚴格按照這種思路進行鏡像設計,你的鏡像是能接受考驗的,而且面試的時候也是能加分的。

鏡像的安全管理

上面聊了那么多鏡像相關的話題,最后再來說說鏡像安全的問題。

鏡像是容器的基石,是應用的載體。最終我們的鏡像是為業務直接或者間接的提供服務,做過運維的同學應該都為自己的操作系統做過安全加固,鏡像其實也需要。

這里不闡述操作系統加固方面的知識,僅僅只針對容器來說。

(1)保持鏡像精簡

精簡不等于安全。

但是精簡的鏡像可以在一定程度上規避一些安全問題,都知道,一個操作系統中是會安裝非常多的軟件,這些軟件每天都會暴露不同的漏洞,這些漏洞就會成為不懷好意之人的目標。我們可以把鏡像看成是一個縮小版的操作系統,同理,鏡像里面的軟件越少,越精簡,其漏洞暴露的風險就更低。

(2)使用非root用戶

容器和虛擬機之間的一個關鍵區別是容器與主機共享內核。在默認情況下,Docker 容器運行在 root 用戶下,這會導致泄露風險。因為如果容器遭到破壞,那么主機的 root 訪問權限也會暴露。

所以我們在制作鏡像的時候要使用非root用戶,比如下面一個java服務:

  1. FROM openjdk:8-jre-alpine 
  2. RUN addgroup -g 1000 -S joker && \ 
  3.     adduser joker -D -G joker -u 1000 -s /bin/sh 
  4. USER joker 
  5. ADD --chown=joker springboot-helloworld.jar /home/joker/app.jar 
  6. EXPOSE 8080 
  7. WORKDIR /home/joker 
  8. CMD  exec java -Djava.security.egd=file:/dev/./urandom -jar app.jar 

(3)對鏡像進行安全掃描

在容器注冊中心運行安全掃描可以為我們帶來額外的價值。除了存放鏡像,鏡像注冊中心定期運行安全掃描可以幫助我們找出薄弱點。Docker 為官方鏡像和托管在 Docker Cloud 的私有鏡像提供了安全掃描。

當然還有其他的倉庫也有集成安全掃描工具,比如Harbor新版本已經可以自定義鏡像掃描規則,也可以定義攔截規則,可以有效的發現鏡像漏洞。

(4)要時常去查看安全結果

大家有沒有這種感覺,我加了很多東西,但是感覺不到?

我有時候就有這種感覺,比如我給某個應用加了監控,然后就不管了,以至于我根本不知道或者不在乎這個監控到底怎么樣。

假如我們對鏡像進行了安全掃描,安裝了一些工具,一定要去查看每個安全結果,而不是掃了就完了。

總結

小小的鏡像就有這么多道道,不看不知道,一看嚇一跳。

本文主要從Docker鏡像的概念說起,然后結合一些實際的場景進行對比分析闡述更深層次的實現過程,有助于幫助大家理解Docker鏡像。

 

責任編輯:姜華 來源: 運維開發故事
相關推薦

2018-11-21 08:00:05

Dubbo分布式系統

2022-02-21 09:44:45

Git開源分布式

2023-05-12 08:19:12

Netty程序框架

2021-06-30 00:20:12

Hangfire.NET平臺

2023-09-06 14:57:46

JavaScript編程語言

2020-12-08 08:09:49

SVG圖標Web

2021-05-18 08:30:42

JavaScript 前端JavaScript時

2021-06-24 09:05:08

JavaScript日期前端

2021-09-27 09:18:30

ListIterato接口方法

2021-01-26 23:46:32

JavaScript數據結構前端

2021-03-05 18:04:15

JavaScript循環代碼

2021-03-09 14:04:01

JavaScriptCookie數據

2024-04-19 14:23:52

SwitchJavaScript開發

2023-07-30 15:18:54

JavaScript屬性

2021-02-26 20:01:57

SVG濾鏡元素

2023-05-08 08:21:15

JavaNIO編程

2024-01-30 13:47:45

2020-11-10 10:48:10

JavaScript屬性對象

2020-02-28 11:29:00

ElasticSear概念類比

2021-06-04 09:56:01

JavaScript 前端switch
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 在线啊v | 亚洲啊v在线 | 免费毛片在线 | 91成人在线 | www.免费看片.com| 国产一区二区三区久久久久久久久 | 一区二区三区视频 | 一区二区三区国产精品 | 亚洲国产精品成人无久久精品 | 综合色播 | 欧美激情久久久 | 99精品视频免费观看 | 亚洲天堂二区 | 免费电影av | 精品美女久久久久久免费 | 天久久| 视频一区二区在线观看 | 男人天堂免费在线 | 久久精彩视频 | 免费成人在线网站 | xx视频在线 | 日韩视频在线免费观看 | 日韩欧美国产精品一区二区三区 | 国产一区二区高清在线 | 综合色导航 | 欧美一级在线观看 | 日韩快播电影 | 日日碰狠狠躁久久躁婷婷 | 国产高清视频一区二区 | 在线成人av | av网站免费在线观看 | 日韩免费一二三区 | 亚洲欧美激情视频 | 91免费入口 | 国产一区二区视频在线 | av性色全交蜜桃成熟时 | 黄色国产在线播放 | 欧美精品一区在线观看 | 欧美韩一区二区三区 | 久久久精品天堂 | 国产成人精品久久 |