<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          每個(gè)前端都要學(xué)的【前端自動(dòng)化部署】,Devops,CI/CD

          共 28495字,需瀏覽 57分鐘

           ·

          2023-09-01 14:35

          大廠(chǎng)技術(shù)  高級(jí)前端  Node進(jìn)階

          點(diǎn)擊上方 程序員成長(zhǎng)指北,關(guān)注公眾號(hào)

          回復(fù)1,加入高級(jí)Node交流群

          前言

          大家好,我是考拉??。

          DevOps

          提到 Jenkins,想到的第一個(gè)概念就是 CI/CD 在這之前應(yīng)該再了解一個(gè)概念。

          DevOps Development 和 Operations 的組合,是一種方法論,并不特指某種技術(shù)或者工具。DevOps 是一種重視 Dev 開(kāi)發(fā)人員和 Ops 運(yùn)維人員之間溝通、協(xié)作的流程。通過(guò)自動(dòng)化的軟件交付,使軟件的構(gòu)建,測(cè)試,發(fā)布更加的快捷、穩(wěn)定、可靠。

          CI

          CI 的英文名稱(chēng)是Continuous Integration,中文翻譯為:持續(xù)集成。

          試想軟件在開(kāi)發(fā)過(guò)程中,需要不斷的提交,合并進(jìn)行單元測(cè)試和發(fā)布測(cè)試版本等等,這一過(guò)程是痛苦的。持續(xù)集成CI是在源代碼變更后自動(dòng)檢測(cè)、拉取、構(gòu)建的過(guò)程。

          ci.png

          CD

          CD 對(duì)應(yīng)兩個(gè)概念 持續(xù)交付Continuous Delivery 持續(xù)部署Continuous Deployment

          持續(xù)交付

          提交交付顧名思義是要拿出點(diǎn)東西的。在 CI 的自動(dòng)化流程階段后,運(yùn)維團(tuán)隊(duì)可以快速、輕松地將應(yīng)用部署到生產(chǎn)環(huán)境中或發(fā)布給最終使用的用戶(hù)。

          從前端的角度考慮,在某些情況下肯定是不能直接通過(guò)自動(dòng)化的方式將最終的 build 結(jié)果直接扔到生產(chǎn)機(jī)的。持續(xù)交互就是可持續(xù)性交付供生產(chǎn)使用的的最終 build。最后通過(guò)運(yùn)維或者后端小伙伴進(jìn)行部署。

          cd1.png

          持續(xù)部署

          作為持續(xù)交付的延伸,持續(xù)部署可以自動(dòng)將應(yīng)用發(fā)布到生產(chǎn)環(huán)境。

          cd2.png

          Jenkins 安裝

          示例服務(wù)器為 阿里云 CentOS 服務(wù)器。安全組中增加 8080 端口 Jenkins 默認(rèn)占用

          Jenkins 安裝大體分兩種方式,一種使用 Docker 另一種則是直接安裝,示例選擇后者。不管使用哪種方式安裝,最終使用層面都是一樣的。 Linux 安裝[1], Docker 安裝[2]

          點(diǎn)擊查看Linux安裝過(guò)程

          # 下載 Jenkins 資源sudo wget -O /etc/yum.repos.d/jenkins.repo https://pkg.jenkins.io/redhat/jenkins.repo# 獲取并導(dǎo)入信任 的包制作者的秘鑰sudo rpm --import https://pkg.jenkins.io/redhat/jenkins.io.key# 升級(jí) yum 源中的所有包sudo yum upgrade# Jenkins 依賴(lài)于 java 所以需要安裝 JDKsudo yum install java-11-openjdk# 安裝 Jenkinssudo yum install jenkins復(fù)制代碼

          如果最終 Jenkins 沒(méi)有找到包而導(dǎo)致沒(méi)有安裝成功,檢查第一步和第二部執(zhí)行結(jié)果并重新執(zhí)行。

          可以使用 systemctl 命令管理 Jenkins 服務(wù) systemctl[3]

          # 啟動(dòng) Jenkins 服務(wù)systemctl start jenkins# 重啟 Jenkins 服務(wù)systemctl restart jenkins# 停止 Jenkins 服務(wù)systemctl stop jenkins# 查看 Jenkins 服務(wù)狀態(tài)systemctl status jenkins復(fù)制代碼

          啟動(dòng)服務(wù)后訪(fǎng)問(wèn)服務(wù)器地址 + 8080 端口,Jenkins 默認(rèn)為 8080 端口。

          Jenkins 使用及 Freestyle 任務(wù)構(gòu)建

          jenkins1.jpg

          首次進(jìn)入使用 cat /var/lib/jenkins/secrets/initialAdminPassword 查看密碼。

          隨后進(jìn)入插件安裝頁(yè)面,暫時(shí)安裝系統(tǒng)推薦插件即可。

          然后創(chuàng)建用戶(hù)

          jenkins2.jpg

          構(gòu)建目標(biāo):拉取 github 代碼

          點(diǎn)擊 新建 Item 創(chuàng)建一個(gè) Freestyle Project

          jenkins3.jpg

          在 源碼管理 處選擇 git ,輸入倉(cāng)庫(kù)地址,點(diǎn)擊添加。

          jenkins4.jpg

          輸入 github 賬號(hào)和密碼,這里的密碼有時(shí)候可能會(huì)出現(xiàn)問(wèn)題,可以使用 token github 如何生成 token ?[4]

          配置只是一方面,同時(shí)服務(wù)器也要具備 git 環(huán)境。 yum install git

          jenkins5.jpg

          構(gòu)建目標(biāo):部署到本機(jī)

          部署前端項(xiàng)目肯定是離不開(kāi) nginx 的。 yum install nginx

          安裝完成后同樣可以使用 systemctl 命令管理 nginx 服務(wù)。

          nginx 具體配置這里就不說(shuō)了。本示例項(xiàng)目中,靜態(tài)文件托管目錄為 /usr/share/nginx/html/dist

          接著來(lái)到 Jenkins 這里。想要部署前端項(xiàng)目還需要依賴(lài)一個(gè) Node 環(huán)境,需要在 Manage Jenkins -> Manage Plugins 在可選插件中搜索 nodejs 選擇對(duì)應(yīng)插件進(jìn)行安裝,安裝完成后需要重啟才會(huì)生效。

          jenkins6.jpg

          然后到 系統(tǒng)管理 -> 全局工具配置 中配置 Node (吐槽:沒(méi)有安裝任何插件時(shí)系統(tǒng)管理以及其子頁(yè)面全是英文,安裝完插件后又變成了中文。這國(guó)際化不知道是系統(tǒng)原因還是它的原因 ??)。

          jenkins7.jpg

          隨后去修改剛才創(chuàng)建的任務(wù)。在 構(gòu)建環(huán)境 中會(huì)多出一個(gè)選項(xiàng) Provide Node & npm bin/ folder to PATH 勾選即可。然后在 構(gòu)建 中選擇 增加構(gòu)建步驟 -> 執(zhí)行 shell 輸入打包發(fā)布相關(guān)的命令。Jenkins 會(huì)逐行執(zhí)行。

          npm install yarn -gyarn installyarn build# 打包 build 后的文件tar -zcvf dist.tar.gz dist/# 刪除 build 后的文件rm -rf dist/# 移動(dòng) build 后的壓縮包到 nginx 托管目錄下。sudo mv dist.tar.gz /usr/share/nginx/html# 進(jìn)入托管目錄下cd /usr/share/nginx/html# 解壓sudo tar -zxcf dist.tar.gz# 刪除壓縮包sudo rm -rf dist.tar.gz復(fù)制代碼
          • 由于項(xiàng)目構(gòu)建時(shí)是在 Jenkins 的工作目錄下執(zhí)行腳本,會(huì)出現(xiàn)權(quán)限問(wèn)題。導(dǎo)致即使使用了 sudo 還會(huì)出現(xiàn)類(lèi)似以下錯(cuò)誤。
          We trust you have received the usual lecture from the local SystemAdministrator. It usually boils down to these three things:    #1) Respect the privacy of others.    #2) Think before you type.    #3) With great power comes great responsibility.復(fù)制代碼

          解決方案:在 /etc/sudoers 文件中增加 jenkins ALL=(ALL) NOPASSWD:ALL 表示在執(zhí)行 sudo 時(shí)不需要輸入密碼。

          • 如果不使用 sudo 則會(huì)出現(xiàn)以下錯(cuò)誤。
          xxxxxxx: Permission denied復(fù)制代碼

          解決方案:修改 /lib/systemed/system/jenkins.service 文件。將 User=jenkins 修改為 User=root,表示給 Jenkins 賦權(quán)限。修改配置文件后記得重啟服務(wù)。

          • 構(gòu)建的過(guò)程中還可能出現(xiàn)以下錯(cuò)誤
          ERROR: Error fetching remote repo 'origin'復(fù)制代碼

          解決方案:由于需要構(gòu)建的代碼在 github 上面,這種錯(cuò)誤表示拉取代碼失敗了,重試幾次就可以了。

          工作目錄

          上面提到一個(gè)很重要的概念就是 工作目錄 在上面的 shell 默認(rèn)就是在這里執(zhí)行的。工作目錄是由兩部分組成。

          • /var/lib/jenkins/workspace/ 類(lèi)似于前綴吧。
          • web-deploy 這個(gè)其實(shí)是上面構(gòu)建任務(wù)的名字。

          總結(jié):Jenkins 的執(zhí)行目錄是 /var/lib/jenkins/workspace/web-deploy。也就是說(shuō)輸入的每一條命令都是在這里面執(zhí)行的。(搞清楚定位能避免好多問(wèn)題,特別是前端的部署,就是打包,移動(dòng),解壓很容易搞錯(cuò)路徑。)

          構(gòu)建目標(biāo):偵聽(tīng) git 提交到指定分支進(jìn)行構(gòu)建

          • 來(lái)到 Jenkins 中選擇 系統(tǒng)管理 -> 系統(tǒng)配置 找到 Jenkins URL 將其復(fù)制。
          • 隨后在尾部添加 github-webhook/ 尾部斜杠一定不要丟。整體結(jié)構(gòu)大致為 http://192.168.0.1:8080/github-webhook/
          • 登錄 github 需要集成的項(xiàng)目中添加 webhook。在 Payload URL 中將上述內(nèi)容填入。
          jenkins8.jpg
          • 然后修改 Jenkins 任務(wù)配置 構(gòu)建觸發(fā)器中選擇 GitHub hook trigger for GITScm polling
          jenkins9.jpg

          由于在上面的源碼管理中已經(jīng)指定了main分支,此時(shí)如果這個(gè)分支的代碼有改動(dòng)就會(huì)觸發(fā)自動(dòng)構(gòu)建。

          構(gòu)建目標(biāo):部署到目標(biāo)主機(jī)

          在真實(shí)的開(kāi)發(fā)場(chǎng)景中,Jenkins 幾乎不會(huì)和前端資源放到一個(gè)服務(wù)器。大多數(shù)情況下 Jenkins 所處的服務(wù)器環(huán)境就是一個(gè)工具用的服務(wù)器,放置了一些公司中常用的工具。因此構(gòu)建到指定的服務(wù)器也至關(guān)重要。

          1,系統(tǒng)管理 -> 插件管理 搜索 Publish Over SSH 進(jìn)行安裝。

          jenkins10.jpg

          2,然后在系統(tǒng)管理 -> 系統(tǒng)配置中找到 Publish over SSH 點(diǎn)擊新增,再點(diǎn)擊高級(jí),然后選中 Use password authentication, or use a different key

          jenkins11.jpg

          完成后可點(diǎn)擊右下角 Test Confirguration 進(jìn)行測(cè)試。

          3,繼續(xù)修改構(gòu)建任務(wù)。先修改原有的構(gòu)建腳本。因?yàn)橐l(fā)布到遠(yuǎn)程,所以原有的發(fā)布命令要進(jìn)行去除。

          npm install yarn -gyarn installyarn build# 只打包,然后刪除文件夾。tar -zcvf dist.tar.gz dist/rm -rf dist/復(fù)制代碼

          4,選擇構(gòu)建后操作 -> Send build artifacts over SSH

          jenkins12.jpg
          • Rransfer Set Source files:要上傳到目標(biāo)服務(wù)器的文件。它是一個(gè)相對(duì)路徑,相對(duì)于 Jenkins 的工作目錄 由于上面的 shell 執(zhí)行之后在工作目錄中只有一個(gè)壓縮包,so 直接寫(xiě)一個(gè)文件名即可。
          • Remove prefix:去前綴。假設(shè)此時(shí)打包文件在 /var/lib/jenkins/workspace/web-deploy/assets/dist.tar.gz,那么 Rransfer Set Source files 則應(yīng)該為 assets/dist.tar.gz,此時(shí) Remove prefix 配置為 assets/ 則可以去除這個(gè)前綴,否則會(huì)在目標(biāo)服務(wù)中創(chuàng)建 assets 。
          • Remote directory:遠(yuǎn)程的靜態(tài)資源托管目錄。由于配置服務(wù)器默認(rèn)為 /,所以 usr/share/nginx/html/ 不用以 / 開(kāi)頭。
          • Exec command:遠(yuǎn)程機(jī)執(zhí)行 shell,由于配置服務(wù)器默認(rèn)為 /, 所以 工作目錄也是以 / 開(kāi)始

          執(zhí)行成功后查看執(zhí)行日志會(huì)有類(lèi)似以下結(jié)果:

          SSH: Connecting from host [iZuf6dwyzch3wm3imzxgqfZ]SSH: Connecting with configuration [aliyun-dev] ...SSH: EXEC: completed after 202 msSSH: Disconnecting configuration [aliyun-dev] ...# 如果 Transferred 0 file 則需要查看配置的路徑是否正確。表示文件并沒(méi)有被移動(dòng)到遠(yuǎn)程主機(jī)中。SSH: Transferred 1 file(s)Finished: SUCCESS復(fù)制代碼

          構(gòu)建目標(biāo):釘釘機(jī)器人通知

          1,系統(tǒng)管理 -> 插件管理 搜索 DingTalk 進(jìn)行安裝。文檔[5]

          jenkins13.jpg

          2,釘釘群創(chuàng)建機(jī)器人。釘釘群 -> 只能群助手 -> 添加機(jī)器人 -> 自定義

          ding1.jpg

          3,定義機(jī)器人名字和關(guān)鍵字,創(chuàng)建完成后先將 webhook 中的內(nèi)容復(fù)制。

          ding2.jpg

          4,Jenkins 中 系統(tǒng)管理 -> 系統(tǒng)配置 -> 釘釘 -> 新增 配置完成后可點(diǎn)擊右下角進(jìn)行測(cè)試。

          jenkins14.jpg

          5,修改構(gòu)建任務(wù)配置。

          jenkins15.jpg
          • 通知人:atAll 勾選后 @ 不到準(zhǔn)確的人。??。輸入框內(nèi)可填寫(xiě)需要被 @ 人的手機(jī)號(hào),多個(gè)換行。
          • 自定義內(nèi)容:支持 markdown 寫(xiě)法,可以使用一些環(huán)境變量。192.168.0.1:8080/env-vars.html/
          • 實(shí)現(xiàn)默認(rèn) `@` 執(zhí)行人[6]

          6,構(gòu)建成功

          ding3.jpg

          Pipline 構(gòu)建

          上一章節(jié)中著重介紹了如何構(gòu)建 freestyle 的任務(wù),但是 Jenkins 遠(yuǎn)不止于此。在本章開(kāi)始之前強(qiáng)烈建議閱讀文檔[7],重點(diǎn)關(guān)注流水線(xiàn)相關(guān)內(nèi)容。

          新建任務(wù) -> 選擇流水線(xiàn) 其他內(nèi)容可以都不用管,只關(guān)注流水線(xiàn) 有兩種選擇,演示就選擇第一種。

          直接在 Jenkins 中書(shū)寫(xiě)配置。

          pipline1.jpg

          在項(xiàng)目的 Jenkinsfile 配置文件中寫(xiě)配置。

          pipline2.jpg

          在正式開(kāi)始之前應(yīng)該了解 Jenkins Pipline 的基礎(chǔ)概念。

          pipeline {    agent any // 在任何可用的代理上,執(zhí)行流水線(xiàn)或它的任何階段。    stages {        stage('Build') { // 定義 "Build" 階段。            steps {                // 執(zhí)行與 "Build" 階段相關(guān)的步驟。            }        }        stage('Deploy') { // 定義 "Deploy" 階段。            steps {                // 執(zhí)行與 "Deploy" 階段相關(guān)的步驟。            }        }    }}復(fù)制代碼
          • pipline:定義流水線(xiàn)整個(gè)結(jié)構(gòu),可以看做是根節(jié)點(diǎn)
          • agent:指示 Jenkins 為整個(gè)流水線(xiàn)分配一個(gè)執(zhí)行器,比如可以配置 Docker
          • stages:對(duì)整個(gè) CI 流的包裹,個(gè)人認(rèn)為沒(méi)多大用,還必須得有。
          • stage:可以理解為是對(duì)某一個(gè)環(huán)節(jié)的描述。注意:參數(shù)就是描述內(nèi)容,可以是任何內(nèi)容。不要想歪了只能傳遞 Build Deploy 這些。
          • steps:描述了 stage 中的步驟,可以存在多個(gè)。

          了解到這里還是不夠的。流水線(xiàn)入門(mén)[8] 流水線(xiàn)語(yǔ)法參考[9]

          Pipline 復(fù)刻 Freestyle

          這里先直接把配置貼出來(lái)。后續(xù)結(jié)合內(nèi)容在進(jìn)行分析。

          點(diǎn)擊查看完整配置

          // 自定義 釘釘插件 的 錯(cuò)誤信息和成功信息def successText = [    """ ### 新的構(gòu)建信息,請(qǐng)注意查收""",    ""${env.JOB_BASE_NAME}任務(wù)構(gòu)建<font color=green>成功</font> ,點(diǎn)擊查看[構(gòu)建任務(wù) #${env.BUILD_NUMBER}](http://106.14.185.47:8080/job/${env.JOB_BASE_NAME}/${env.BUILD_NUMBER}/)"""]def failureText = [    """ ### 新的構(gòu)建信息,請(qǐng)注意查收""",    ""${env.JOB_BASE_NAME}任務(wù)構(gòu)建<font color=red>失敗</font> ,點(diǎn)擊查看[構(gòu)建任務(wù) #${env.BUILD_NUMBER}](http://106.14.185.47:8080/job/${env.JOB_BASE_NAME}/${env.BUILD_NUMBER}/)"""]// 1,偵聽(tīng) github push 事件properties([pipelineTriggers([githubPush()])])pipeline {    agent any    // 環(huán)境變量定義。    environment {        GIT_REPO = 'http://github.com/vue-ts-vite-temp.git'    }    stages {        // 2,拉取 github 代碼,通過(guò) GitSCM 偵聽(tīng) push 事件。        stage('Pull code') {            steps {                checkout(                    [                        $class'GitSCM',                        branches: [[name: '*/main']],                        extensions: [],                        userRemoteConfigs: [                            [                                credentialsId: '381325e4-0f9c-41ea-b5f6-02f8ea2a475a',                                url: env.GIT_REPO                            ]                        ],                        changelog: true,                        poll: true,                    ]                )            }        }        stage('Install and build') {            steps {                // 3,前面安裝過(guò)的 nodejs 插件使用                nodejs('v14.19.0') {                    sh 'npm install yarn -g'                    sh 'yarn install'                    sh 'yarn build'                }            }        }        stage('Pack') {            steps {                sh 'tar -zcvf dist.tar.gz dist/'                sh 'rm -rf dist/'            }        }        stage('Deploy') {            steps {                // 4,前面下載的 Publish Over SSH 插件的使用                sshPublisher(                    publishers: [                        sshPublisherDesc(                            configName: 'aliyun-dev',                            transfers: [                                sshTransfer(                                    cleanRemote: false,                                    excludes: '',                                    execCommand: '''                                        cd /usr/share/nginx/html/                                        tar -zxvf dist.tar.gz                                        rm -rf dist.tar.gz                                    ''',                                    execTimeout: 120000,                                    flatten: false,                                    makeEmptyDirs: false,                                    noDefaultExcludes: false,                                    patternSeparator: '[, ]+',                                    remoteDirectory: '/usr/share/nginx/html/',                                    remoteDirectorySDF: false,                                    removePrefix: '',                                    sourceFiles: 'dist.tar.gz'                                )                            ],                            usePromotionTimestamp: false,                            useWorkspaceInPromotion: false,                            verbose: false                        )                    ]                )            }        }    }    post {        success {            // 5,DingTalk 插件的使用。            dingtalk (                robot: '1314',                type'ACTION_CARD',                title: 'Jenkins構(gòu)建提醒',                text: successText,                btns: [                    [                        title: '控制臺(tái)',                        actionUrl: 'http://106.14.185.11:8080/'                    ],                    [                        title: '項(xiàng)目預(yù)覽',                        actionUrl: 'http://github.com/'                    ],                ],                at: []            )        }        failure {            dingtalk(                robot: '1314',                type'ACTION_CARD',                title: 'Jenkins構(gòu)建提醒',                text: failureText,                btns: [                    [                        title: '控制臺(tái)',                        actionUrl: 'http://106.14.185.11:8080/'                    ],                    [                        title: '項(xiàng)目預(yù)覽',                        actionUrl: 'http://github.com/'                    ],                ],                at: []// 這里是手機(jī)號(hào)多個(gè)之間,隔開(kāi)            )        }    }}復(fù)制代碼

          這么多內(nèi)容手寫(xiě)無(wú)疑是很難受的,好在 Jenkins 提供了一些幫助工具。訪(fǎng)問(wèn)地址為:Jenkins地址 + /job + 當(dāng)前任務(wù) + /pipeline-syntax/,例如:http://localhost:8080/job/dev-deploy/pipeline-syntax/,或者進(jìn)入任務(wù)構(gòu)建頁(yè)面,點(diǎn)擊流水線(xiàn)語(yǔ)法進(jìn)入

          pipline3.jpg

          進(jìn)入該頁(yè)面后請(qǐng)熟讀并背誦以下三項(xiàng)。重點(diǎn)放到第一項(xiàng)。

          pipline4.jpg

          回頭看上面的腳本注釋都帶有序號(hào)。根據(jù)注釋序號(hào)開(kāi)始解釋。

          1,在片段生成器中選擇 properties: Set job properties 生成代碼片段。由于只是使用了 git hook trigger 所以要對(duì)生成的片段稍作修改。

          pipline5.jpg

          2,如果不是為了偵聽(tīng) github push 選擇 git: Git 即可,但現(xiàn)在應(yīng)該選擇 checkout: Check out from version control,隨后填寫(xiě)信息生成代碼即可。

          pipline6.jpg

          3,選擇 nodejs: Provide Node & npm bin/folder to Path

          pipline7.jpg

          4,選擇 sshPublisher: Send build artifacts over SSH,像上面流水線(xiàn)一樣配置之后直接生成代碼即可。

          pipline8.jpg

          5,DingTalk 文檔

          總結(jié): 通過(guò)插件生成的代碼,稍作組合就成為了完整的配置。但整體難度還是要略高于 Freestyle 任務(wù)。畢竟生成的代碼有部分也不是拿來(lái)即用的,并且 Pipline 基本語(yǔ)法一定要有所掌握。不然生成的代碼都不曉得放到哪里合適。

          作者:65歲退休Coder

          鏈接:https://juejin.cn/post/7102360505313918983

          來(lái)源:稀土掘金

          結(jié)語(yǔ)

          Node 社群

              
              


          我組建了一個(gè)氛圍特別好的 Node.js 社群,里面有很多 Node.js小伙伴,如果你對(duì)Node.js學(xué)習(xí)感興趣的話(huà)(后續(xù)有計(jì)劃也可以),我們可以一起進(jìn)行Node.js相關(guān)的交流、學(xué)習(xí)、共建。下方加 考拉 好友回復(fù)「Node」即可。

             “分享、點(diǎn)贊在看” 支持一下

          瀏覽 2921
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  蜜臀尤物一区二区三区直播 | 99综合在线 | 毛片网站大全免费在线观看 | 日本一极黄色 | 亚洲 偷拍 在线 无码 制服 另类 |