亚洲有码Av一区二区三区_国产高清啪啪免费视频_69色视频国产_国产成人人人爆出白浆_国产精品自在线拍国_一本久久伊人热热精品无码_午夜性刺激在线看免费带字幕_助力高品质欧美狂喷水_亚洲精品日韩无码_精品无码一区二区三区蜜臀_麻豆高清国产AV_熟妇人素无码中文字幕_亚洲a级片在线观看_国产欧美日韩三区_99国产成人高清在线观看

ARTICLE DETAIL

資訊詳情

深耕商務(wù)建站與企業(yè)官網(wǎng)運(yùn)營(yíng)的一線實(shí)戰(zhàn)洞察。

NestJS+Prisma+Docker容器化實(shí)踐:從環(huán)境搭建到遷移排錯(cuò)全指南

NestJS+Prisma+Docker容器化實(shí)踐:從環(huán)境搭建到遷移排錯(cuò)全指南 本地跑得好好的一放進(jìn) Docker 就翻車(chē)——這是我在接觸 NestJS、Prisma、Docker 這個(gè)組合之后見(jiàn)過(guò)最多的吐槽。三個(gè)工具單個(gè)拿出來(lái)都很穩(wěn)定但一旦綁在一起數(shù)據(jù)庫(kù)地址、遷移時(shí)機(jī)、二進(jìn)制依賴(lài)、文件掛載這些細(xì)節(jié)就會(huì)連環(huán)踩坑。這套技術(shù)棧如今幾乎是后端服務(wù)的標(biāo)配組合NestJS 提供模塊化和依賴(lài)注入Prisma 讓數(shù)據(jù)庫(kù)操作從 SQL 拼接變成類(lèi)型安全的調(diào)用Docker 則把整個(gè)環(huán)境固化下來(lái)。這篇內(nèi)容就圍繞這三個(gè)工具的實(shí)際開(kāi)發(fā)流程展開(kāi)從空目錄搭到生產(chǎn)鏡像中間把連接池、熱重載、遷移執(zhí)行順序這些最容易出問(wèn)題的地方一并講清楚。適合正在用 NestJS 寫(xiě)業(yè)務(wù)、想引入 Prisma 又打算容器化的團(tuán)隊(duì)和個(gè)人參考。1. 組合選型NestJS、Prisma、Docker 三者為什么是黃金搭檔1.1 三個(gè)工具各自的定位先說(shuō)清楚它們各自解決什么。NestJS 是一個(gè) Node.js 服務(wù)端框架它給了你模塊化、依賴(lài)注入、裝飾器、守衛(wèi)、攔截器這一整套組織代碼的方式。它的價(jià)值不在于某個(gè)黑科技功能而在于把大型應(yīng)用的代碼邊界約束住讓不同人寫(xiě)的模塊之間不會(huì)亂成一團(tuán)。Prisma 是數(shù)據(jù)庫(kù) ORM但它不是傳統(tǒng)意義上那種把表映射成對(duì)象的 ORM而是把你的數(shù)據(jù)庫(kù)表結(jié)構(gòu)定義在 schema 文件里然后生成一套類(lèi)型安全的查詢(xún)客戶(hù)端。寫(xiě)錯(cuò)了表名、字段名編譯期就能發(fā)現(xiàn)而不是等到線上接口報(bào) 500。Docker 解決的是環(huán)境一致性問(wèn)題開(kāi)發(fā)機(jī)、測(cè)試機(jī)、生產(chǎn)機(jī)的操作系統(tǒng)和依賴(lài)版本一旦有細(xì)微差異就會(huì)出現(xiàn)在我這是好的這種經(jīng)典事故。單獨(dú)看這三個(gè)工具都不稀奇。但如果把它們組合起來(lái)整個(gè)開(kāi)發(fā)鏈路會(huì)非常順滑。NestJS 的依賴(lài)注入讓 PrismaService 可以以一個(gè)全局模塊的形式注入到任意業(yè)務(wù)模塊里不需要到處手動(dòng) new PrismaClient()。Docker 則確保每個(gè)人拉下來(lái)鏡像后數(shù)據(jù)庫(kù)版本和 Node 版本完全一致不會(huì)出現(xiàn) A 同學(xué)用 MySQL 5.7、B 同學(xué)用 MySQL 8.0 導(dǎo)致 SQL 行為不一致的情況。1.2 團(tuán)隊(duì)協(xié)作中的一致性收益我個(gè)人認(rèn)為這套組合最大的收益不是技術(shù)層面的而是協(xié)作效率層面的。舉個(gè)例子一個(gè)新同事入職按照傳統(tǒng)的開(kāi)發(fā)流程他要先裝 Node、裝數(shù)據(jù)庫(kù)、導(dǎo)入初始化數(shù)據(jù)折騰半天。用 Docker 之后只需要一條 docker compose up -d數(shù)據(jù)庫(kù)和中間件全部就緒再跑一個(gè) npm run start:dev 就能開(kāi)始寫(xiě)業(yè)務(wù)。而 Prisma 的存在讓數(shù)據(jù)庫(kù)結(jié)構(gòu)變成了代碼的一部分schema.prisma 文件一改遷移記錄一執(zhí)行所有人的表結(jié)構(gòu)都是同步的省掉了大量你建表了嗎為什么我本地少了這個(gè)字段的溝通成本。NestJS 在這套組合里負(fù)責(zé)把業(yè)務(wù)模塊的邊界立起來(lái)它不會(huì)幫你去管理數(shù)據(jù)庫(kù)但它能讓你優(yōu)雅地把 PrismaService 封裝起來(lái)在請(qǐng)求處理中統(tǒng)一事務(wù)和異常處理。所以這套組合的定位可以概括成一句話NestJS 決定代碼怎么組織Prisma 決定數(shù)據(jù)怎么訪問(wèn)Docker 決定環(huán)境怎么統(tǒng)一。理解了這個(gè)分工后面配置起來(lái)就不會(huì)覺(jué)得這里改一點(diǎn)、那里改一點(diǎn)而是能搞清楚每一處配置是在解決哪個(gè)層面的問(wèn)題。2. 開(kāi)發(fā)環(huán)境搭建從空目錄到能跑通第一個(gè)接口2.1 初始化項(xiàng)目與依賴(lài)安裝搭建過(guò)程不復(fù)雜但有幾個(gè)順序容易搞錯(cuò)。先用 CLI 初始化 NestJS 項(xiàng)目再安裝 Prisma 相關(guān)依賴(lài)最后編寫(xiě) schema 文件并生成客戶(hù)端。如果你反過(guò)來(lái)先裝了 Prisma 再初始化 Nest 項(xiàng)目CLI 可能會(huì)因?yàn)闄z測(cè)到已有 node_modules 而跳過(guò)一些依賴(lài)安裝步驟反而埋下隱患。nest new nest-prisma-demo cd nest-prisma-demo npm install prisma --save-dev npm install prisma/client這里注意prisma 是命令行工具放在 devDependencies 里prisma/client 是運(yùn)行時(shí)依賴(lài)必須放在 dependencies 里。很多人圖省事把 prisma 也裝到 dependencies結(jié)果生產(chǎn)鏡像體積白白多出幾十 MB其實(shí)完全沒(méi)有必要。初始化 Prisma 的時(shí)候默認(rèn)連接的是 PostgreSQLnpx prisma init --datasource-provider postgresql這個(gè)命令會(huì)生成 prisma/schema.prisma 和 .env 文件。如果你的數(shù)據(jù)庫(kù)是 MySQL把 postgresql 換成 mysql 即可。生成的 .env 里有一條 DATABASE_URL連接字符串的格式如下DATABASE_URLpostgresql://demo:demo123localhost:5432/demo_db?schemapublic格式拆開(kāi)看就是 postgresql://用戶(hù)名:密碼主機(jī):端口/數(shù)據(jù)庫(kù)名?連接參數(shù)。用戶(hù)名、密碼、庫(kù)名要和后面的 docker-compose 配置完全對(duì)應(yīng)否則后面會(huì)出現(xiàn)認(rèn)證失敗或數(shù)據(jù)庫(kù)不存在的問(wèn)題。2.2 編寫(xiě)最小可用的 Prisma Schema再往 schema.prisma 里寫(xiě)入第一張表。沒(méi)必要一上來(lái)設(shè)計(jì)復(fù)雜業(yè)務(wù)表先建一張 user 表驗(yàn)證鏈路通不通就行g(shù)enerator client { provider prisma-client-js } datasource db { provider postgresql url env(DATABASE_URL) } model User { id Int id default(autoincrement()) email String unique name String? createdAt DateTime default(now()) updatedAt DateTime updatedAt }寫(xiě)完后執(zhí)行 npx prisma migrate dev --name init它會(huì)創(chuàng)建數(shù)據(jù)庫(kù)表并生成 Prisma Client。這里有個(gè)新手容易懵的點(diǎn)migrate dev 命令會(huì)先檢查數(shù)據(jù)庫(kù)里有沒(méi)有遷移記錄再對(duì)比 schema 文件的變化最后生成新的遷移 SQL。這個(gè)命令是開(kāi)發(fā)環(huán)境專(zhuān)用的后面生產(chǎn)環(huán)境要用的是另一個(gè)命令 migrate deploy兩者的區(qū)別我放在第五章專(zhuān)門(mén)講。2.3 把 PrismaService 接入 NestJS 依賴(lài)注入表建好了現(xiàn)在將 Prisma 集成進(jìn) NestJS。比較規(guī)范的做法是建一個(gè) PrismaModule把 PrismaService 作為全局模塊導(dǎo)出這樣任何一個(gè)業(yè)務(wù)模塊的構(gòu)造函數(shù)里都能直接注入不用每個(gè)模塊都去 import。import { Global, Module } from nestjs/common; import { PrismaService } from ./prisma.service; Global() Module({ providers: [PrismaService], exports: [PrismaService], }) export class PrismaModule {}PrismaService 本身繼承 PrismaClient并且在模塊初始化時(shí)建立連接import { Injectable, OnModuleDestroy, OnModuleInit } from nestjs/common; import { PrismaClient } from prisma/client; Injectable() export class PrismaService extends PrismaClient implements OnModuleInit, OnModuleDestroy { async onModuleInit() { await this.$connect(); } async onModuleDestroy() { await this.$disconnect(); } }在根模塊 AppModule 里引入 PrismaModule 后寫(xiě)一個(gè)簡(jiǎn)單的 controller 測(cè)試鏈路。整體思路是先讓 PrismaService 注入到 service 里再通過(guò) controller 暴露一個(gè)返回用戶(hù)列表的接口。跑到這一步如果接口能正常返回?cái)?shù)據(jù)就說(shuō)明 NestJS 和 Prisma 這部分已經(jīng)打通了接下來(lái)要考慮的是怎么把它整個(gè)塞進(jìn) Docker。3. Prisma 連接數(shù)據(jù)庫(kù)的關(guān)鍵配置與連接池調(diào)優(yōu)3.1 DATABASE_URL 在容器內(nèi)外的區(qū)別連接字符串這塊是整套配置里最容易出錯(cuò)的地方。本地開(kāi)發(fā)時(shí)數(shù)據(jù)庫(kù)跑在本地DATABASE_URL 的主機(jī)名寫(xiě)成 localhost 沒(méi)問(wèn)題。但一旦應(yīng)用跑進(jìn) Docker 容器情況就變了。容器是一個(gè)獨(dú)立的網(wǎng)絡(luò)命名空間容器里的 localhost 指向它自己而不是宿主機(jī)的數(shù)據(jù)庫(kù)。假設(shè)你在 docker-compose 里定義了一個(gè)名為 postgres 的數(shù)據(jù)庫(kù)服務(wù)那么應(yīng)用容器里訪問(wèn)數(shù)據(jù)庫(kù)的主機(jī)名要寫(xiě)成 postgres而不是 localhost。這兩個(gè)環(huán)境的配置需要分開(kāi)管理。我習(xí)慣的做法是在根目錄放一個(gè) .env 文件本地開(kāi)發(fā)用它在 docker-compose.yml 里的 environment 節(jié)點(diǎn)單獨(dú)覆蓋 DATABASE_URL用容器網(wǎng)絡(luò)內(nèi)的服務(wù)名。兩者互不干擾也不會(huì)出現(xiàn)本地能跑、容器里連不上數(shù)據(jù)庫(kù)的情況。# 本地開(kāi)發(fā) .env DATABASE_URLpostgresql://demo:demo123localhost:5432/demo_db?schemapublic # docker-compose 中 app 服務(wù)的環(huán)境變量 DATABASE_URLpostgresql://demo:demo123postgres:5432/demo_db?schemapublic另外還要注意Prisma 讀取 .env 文件是默認(rèn)行為但它不會(huì)自動(dòng)加載容器里的 Docker 環(huán)境變量到 NestJS 的 process.env。也就是說(shuō)如果你在 docker-compose 里設(shè)置了 DATABASE_URL但 Prisma schema 里用的是 env(DATABASE_URL)Prisma CLI 在容器內(nèi)執(zhí)行命令時(shí)仍然會(huì)優(yōu)先讀 .env 文件。如果 .env 里也寫(xiě)了 DATABASE_URL就會(huì)覆蓋 docker-compose 里傳入的變量。解決方式是在 .env 文件里不寫(xiě) DATABASE_URL或者給 docker-compose 里的變量名換個(gè)前綴再傳給 Prisma比如DATABASE_URL${DOCKER_DATABASE_URL:-postgresql://demo:demo123localhost:5432/demo_db?schemapublic}這個(gè)寫(xiě)法有點(diǎn)繞但理解了Prisma CLI 優(yōu)先讀 .env應(yīng)用運(yùn)行時(shí)讀 process.env這個(gè)底層邏輯后你就能解釋很多莫名其妙的問(wèn)題。3.2 連接池大小與超時(shí)配置Prisma 默認(rèn)有一個(gè)連接池機(jī)制不會(huì)每次查詢(xún)都新建數(shù)據(jù)庫(kù)連接而是維護(hù)一批連接反復(fù)使用。在 PostgreSQL 數(shù)據(jù)源下默認(rèn)連接池大小是 CPU 核心數(shù)乘以 2 再加 1。這個(gè)值在大多數(shù)場(chǎng)景下夠用但如果你在容器里把 CPU 限制設(shè)得比較大又跑著多個(gè)應(yīng)用實(shí)例共享同一個(gè)數(shù)據(jù)庫(kù)就可能把數(shù)據(jù)庫(kù)的連接數(shù)撐爆。連接池大小和超時(shí)都可以在連接字符串里通過(guò)參數(shù)控制DATABASE_URLpostgresql://demo:demo123postgres:5432/demo_db?schemapublicconnection_limit5connect_timeout5pool_timeout10connection_limit 控制連接池上限connect_timeout 控制建立連接的超時(shí)秒數(shù)pool_timeout 控制從連接池拿連接的等待秒數(shù)。設(shè)置連接池上限時(shí)要結(jié)合數(shù)據(jù)庫(kù)自身的 max_connections 參數(shù)來(lái)算例如 PostgreSQL 默認(rèn) max_connections 是 100你有 4 個(gè)應(yīng)用實(shí)例每個(gè)實(shí)例的連接池限到 20加起來(lái)就是 80留一點(diǎn)余量給管理連接這樣的分配是合理的。3.3 連接報(bào)錯(cuò)的分類(lèi)判斷遇到連接問(wèn)題不要盲改代碼先看報(bào)錯(cuò)碼。Prisma 的錯(cuò)誤碼很有規(guī)律根據(jù) P 開(kāi)頭后面的數(shù)字就能快速定位問(wèn)題類(lèi)型錯(cuò)誤碼含義常見(jiàn)原因P1000認(rèn)證失敗用戶(hù)名密碼錯(cuò)誤或數(shù)據(jù)庫(kù)用戶(hù)不存在P1001無(wú)法訪問(wèn)數(shù)據(jù)庫(kù)服務(wù)器主機(jī)名錯(cuò)誤、端口未暴露、網(wǎng)絡(luò)不通P1002數(shù)據(jù)庫(kù)服務(wù)器響應(yīng)超時(shí)防火墻攔截或數(shù)據(jù)庫(kù)負(fù)載過(guò)高P1003數(shù)據(jù)庫(kù)不存在指定的 database 沒(méi)有創(chuàng)建P2024連接池超時(shí)連接池被占滿(mǎn)或者查詢(xún)執(zhí)行過(guò)慢占用了連接P2002唯一約束沖突插入的數(shù)據(jù)重復(fù)了通常是 email 這類(lèi)唯一字段定位思路是先用數(shù)據(jù)庫(kù)客戶(hù)端手動(dòng)連一下確認(rèn)數(shù)據(jù)庫(kù)本身沒(méi)問(wèn)題再看應(yīng)用容器到數(shù)據(jù)庫(kù)的網(wǎng)絡(luò)是否通。如果手動(dòng)能連、應(yīng)用連不上十有八九是連接字符串里的主機(jī)名或端口寫(xiě)錯(cuò)了。如果主機(jī)名和端口都對(duì)但還是 P1001就需要進(jìn)應(yīng)用容器里用 ping 或 nc 測(cè)一下網(wǎng)絡(luò)。容器的網(wǎng)絡(luò)問(wèn)題在第四章會(huì)繼續(xù)展開(kāi)。4. docker-compose 編排開(kāi)發(fā)環(huán)境的掛載與熱重載細(xì)節(jié)4.1 數(shù)據(jù)庫(kù)服務(wù)的選型與數(shù)據(jù)持久化開(kāi)發(fā)環(huán)境用 docker-compose 編排最典型的架構(gòu)是兩個(gè)服務(wù)一個(gè)是數(shù)據(jù)庫(kù)一個(gè)是應(yīng)用本身。數(shù)據(jù)庫(kù)服務(wù)選定鏡像后有兩個(gè)關(guān)鍵點(diǎn)要注意版本和持久化。services: postgres: image: postgres:16-alpine container_name: demo_postgres restart: unless-stopped environment: POSTGRES_USER: demo POSTGRES_PASSWORD: demo123 POSTGRES_DB: demo_db ports: - 5432:5432 volumes: - postgres_data:/var/lib/postgresql/data healthcheck: test: [CMD-SHELL, pg_isready -U demo -d demo_db] interval: 5s timeout: 5s retries: 5 volumes: postgres_data:數(shù)據(jù)庫(kù)鏡像的版本一定要鎖定postgres:16-alpine 里的 16 是主版本alpine 是精簡(jiǎn)系統(tǒng)鏡像。不要用 latest因?yàn)橹靼姹旧?jí)后數(shù)據(jù)目錄的兼容性可能會(huì)出問(wèn)題。持久化卷 postgres_data 掛載到容器內(nèi)的 /var/lib/postgresql/data這樣即使容器刪了重建數(shù)據(jù)也還在。我第一次沒(méi)掛卷docker compose down 之后再 up 起來(lái)表全沒(méi)了只能重新遷移白折騰了半天。healthcheck 這一段很重要。數(shù)據(jù)庫(kù)容器啟動(dòng)后并不代表可以接受連接PostgreSQL 初始化需要幾秒鐘。如果沒(méi)有健康檢查應(yīng)用容器啟動(dòng)時(shí)數(shù)據(jù)庫(kù)可能還沒(méi)就緒Prisma 連接就會(huì)報(bào) P1001 或者超時(shí)。4.2 應(yīng)用服務(wù)的掛載與熱重載應(yīng)用服務(wù)的配置相比數(shù)據(jù)庫(kù)要復(fù)雜一些核心是代碼掛載與 node_modules 的處理。app: build: context: . dockerfile: Dockerfile container_name: demo_app restart: unless-stopped command: npm run start:dev ports: - 3000:3000 volumes: - .:/usr/src/app - /usr/src/app/node_modules environment: DATABASE_URL: postgresql://demo:demo123postgres:5432/demo_db?schemapublic depends_on: postgres: condition: service_healthy第一行掛載 .:/usr/src/app 把宿主機(jī)代碼同步到容器里改完代碼立即觸發(fā) NestJS 的 watch 機(jī)制重啟。第二行 /usr/src/app/node_modules 是一個(gè)匿名卷它的作用是讓容器里安裝的依賴(lài)不會(huì)被宿主機(jī)目錄覆蓋掉。如果不加這一行宿主機(jī)沒(méi)有 node_modules或者版本不同時(shí)容器里的 node_modules 會(huì)被宿主機(jī)的空目錄遮蔽導(dǎo)致啟動(dòng)時(shí)報(bào)找不到模塊。開(kāi)發(fā)模式的啟動(dòng)命令是 npm run start:dev內(nèi)部實(shí)際上跑的是 nest start --watch。這里會(huì)遇到一個(gè)常見(jiàn)的坑在容器內(nèi)監(jiān)聽(tīng)文件變化時(shí)如果文件系統(tǒng)的事件傳遞不及時(shí)NestJS 可能不會(huì)自動(dòng)重啟。解決方式是在 nest-cli.json 里加上 watchOptions 配置{ collection: nestjs/schematics, sourceRoot: src, compilerOptions: { watchOptions: { watchFile: fixedPollingInterval, watchDirectory: fixedPollingInterval, fallbackPolling: interval, interval: 1000 } } }尤其是 macOS 下結(jié)合 Docker Desktop 的虛擬化文件系統(tǒng)事件監(jiān)聽(tīng)經(jīng)常會(huì)失靈啟用輪詢(xún)模式是成本最低的解法代價(jià)是 CPU 占用會(huì)上升一些開(kāi)發(fā)期可以接受。4.3 啟動(dòng)順序與依賴(lài)就緒的完整保障depends_on 配置了 postgres 的 healthcheck 條件能確保數(shù)據(jù)庫(kù)真正就緒后再啟動(dòng)應(yīng)用。這比默認(rèn)的 depends_on 只保證容器啟動(dòng)順序要可靠得多。但這里還有一個(gè)隱藏問(wèn)題Prisma Client 是應(yīng)用啟動(dòng)時(shí)要加載的依賴(lài)它必須在數(shù)據(jù)庫(kù)連接之前已經(jīng)生成好。如果你的 Dockerfile 里沒(méi)有在構(gòu)建階段運(yùn)行 prisma generate容器啟動(dòng)后第一次執(zhí)行遷移或查詢(xún)時(shí)會(huì)報(bào)錯(cuò)找不到 Prisma Client。所以完整的開(kāi)發(fā)鏡像 Dockerfile 至少是這樣的FROM node:20-slim WORKDIR /usr/src/app COPY package*.json ./ RUN npm install COPY prisma ./prisma/ RUN npx prisma generate COPY . . EXPOSE 3000 CMD [npm, run, start:dev]注意 prisma generate 要放在 COPY . . 之前因?yàn)?prisma/schema.prisma 是 generate 的輸入而源碼 copy 之后如果又修改了 schema還需要重新 generate。開(kāi)發(fā)模式下每次 npm install 之后也應(yīng)該手動(dòng)跑一次 npx prisma generate否則新生成的 schema 變更不會(huì)反映到 prisma/client 里。5. 遷移與種子數(shù)據(jù)在容器化環(huán)境里執(zhí)行 Prisma 的正確姿勢(shì)5.1 搞清楚 migrate dev 和 migrate deploy 的區(qū)別Prisma 有兩個(gè)長(zhǎng)得非常像的命令混用的后果很?chē)?yán)重。migrate dev 是開(kāi)發(fā)環(huán)境專(zhuān)用它會(huì)檢查 schema 變更、生成遷移 SQL、創(chuàng)建影子數(shù)據(jù)庫(kù)來(lái)驗(yàn)證遷移可執(zhí)行并且自動(dòng)重新生成 Prisma Client。整個(gè)過(guò)程交互性很強(qiáng)適合你自己開(kāi)發(fā)的時(shí)候用。migrate deploy 則是純執(zhí)行遷移文件它不會(huì)生成新的遷移也不會(huì)去比對(duì) schema 和數(shù)據(jù)庫(kù)的差異只會(huì)把 migrations 目錄下還沒(méi)執(zhí)行過(guò)的遷移按順序應(yīng)用到數(shù)據(jù)庫(kù)。這是個(gè)無(wú)狀態(tài)、冪等、適合在 CI 或生產(chǎn)環(huán)境跑的命令。在 Docker 場(chǎng)景下的正確流程是這樣的本地開(kāi)發(fā)時(shí)用 migrate dev 創(chuàng)建并打磨遷移文件這些遷移文件隨代碼一起提交到倉(cāng)庫(kù)容器啟動(dòng)或部署時(shí)用 migrate deploy 應(yīng)用遷移。不要在容器里跑 migrate dev因?yàn)槊看稳萜髦亟ê笏羞w移都會(huì)重新生成一遍遷移文件會(huì)膨脹得很快而且影子數(shù)據(jù)庫(kù)的創(chuàng)建也需要額外權(quán)限沒(méi)必要。5.2 容器內(nèi)執(zhí)行遷移的兩種路徑遷移在開(kāi)發(fā)環(huán)境里的執(zhí)行時(shí)機(jī)有兩種選擇我分別說(shuō)下優(yōu)劣。第一種是啟動(dòng)時(shí)執(zhí)行。在 app 的 command 里改成類(lèi)似這樣的腳本command: sh -c npx prisma migrate deploy npm run start:dev好處是簡(jiǎn)單每次容器啟動(dòng)都自動(dòng)遷移團(tuán)隊(duì)里任何一個(gè)人 pull 完代碼啟動(dòng)服務(wù)數(shù)據(jù)庫(kù)結(jié)構(gòu)就是最新的。壞處是如果多個(gè)實(shí)例同時(shí)啟動(dòng)兩條 migrate deploy 并發(fā)執(zhí)行可能產(chǎn)生鎖沖突。開(kāi)發(fā)環(huán)境單實(shí)例場(chǎng)景下問(wèn)題不大。第二種是手動(dòng)執(zhí)行。只在需要的時(shí)候進(jìn)入容器執(zhí)行docker compose exec app npx prisma migrate deploy好處是可控缺點(diǎn)是容易忘記遷移導(dǎo)致同事之間表結(jié)構(gòu)不一致。我個(gè)人在開(kāi)發(fā)環(huán)境更推薦第一種省心在測(cè)試或預(yù)發(fā)環(huán)境則建議放在 CI 階段執(zhí)行避免每次發(fā)版都隱式改數(shù)據(jù)庫(kù)結(jié)構(gòu)。5.3 種子數(shù)據(jù)自動(dòng)化的實(shí)現(xiàn)開(kāi)發(fā)環(huán)境里沒(méi)有種子數(shù)據(jù)很多接口測(cè)試沒(méi)法進(jìn)行。Prisma 的 seed 支持在 package.json 中聲明命令然后在遷移之后自動(dòng)執(zhí)行{ prisma: { seed: ts-node prisma/seed.ts }, scripts: { prisma:seed: prisma db seed } }seed.ts 文件內(nèi)容大致長(zhǎng)這樣import { PrismaClient } from prisma/client; const prisma new PrismaClient(); async function main() { await prisma.user.upsert({ where: { email: demoexample.com }, update: {}, create: { email: demoexample.com, name: Demo User, }, }); } main() .catch((e) { console.error(e); process.exit(1); }) .finally(async () { await prisma.$disconnect(); });在容器里執(zhí)行 seed 有一個(gè)依賴(lài)層面的坑如果開(kāi)發(fā)鏡像里只安裝了 dependencies 而沒(méi)有安裝 devDependencies那么 ts-node 不存在seed 腳本就會(huì)執(zhí)行失敗。更穩(wěn)妥的做法是在開(kāi)發(fā)鏡像里把 ts-node 裝上或者直接用編譯后的 JavaScript 寫(xiě)種子腳本避免對(duì) ts-node 的運(yùn)行時(shí)依賴(lài)。種子腳本執(zhí)行頻率也要控制用 upsert 而不是 create 可以避免重復(fù)執(zhí)行時(shí)報(bào)唯一約束錯(cuò)誤。6. 生產(chǎn)鏡像構(gòu)建多階段編譯與 Prisma 引擎體積控制6.1 多階段構(gòu)建的三個(gè)階段開(kāi)發(fā)鏡像是怎么方便怎么來(lái)但生產(chǎn)鏡像的要求不同體積要小、沒(méi)有冗余文件、不包含源碼、不暴露開(kāi)發(fā)依賴(lài)。多階段構(gòu)建是標(biāo)準(zhǔn)解法把一個(gè) Dockerfile 拆成三個(gè)階段FROM node:20-slim AS base RUN apt-get update apt-get install -y openssl rm -rf /var/lib/apt/lists/* FROM node:20-slim AS builder WORKDIR /build RUN apt-get update apt-get install -y openssl rm -rf /var/lib/apt/lists/* COPY package*.json ./ RUN npm ci COPY prisma ./prisma/ RUN npx prisma generate COPY tsconfig.json nest-cli.json ./ COPY src ./src RUN npm run build FROM node:20-slim AS runner RUN apt-get update apt-get install -y openssl rm -rf /var/lib/apt/lists/* WORKDIR /app ENV NODE_ENVproduction COPY --frombuilder /build/package*.json ./ RUN npm ci --omitdev npm cache clean --force COPY --frombuilder /build/node_modules/.prisma ./node_modules/.prisma COPY --frombuilder /build/dist ./dist EXPOSE 3000 CMD [node, dist/main.js]三個(gè)階段的職責(zé)分別是base 提供公共基礎(chǔ)builder 編譯源碼并生成 Prisma Clientrunner 只保留運(yùn)行時(shí)所需的最小文件。pro 這里容易踩的第一個(gè)坑是 openssl 缺失。Prisma 的查詢(xún)引擎底層依賴(lài) OpenSSL而 node:20-slim 這個(gè)精簡(jiǎn)鏡像不帶 openssl直接跑起來(lái)會(huì)報(bào)錯(cuò)提示找不到 libssl.so 之類(lèi)。所以每一層需要運(yùn)行 Prisma Client 的階段都要安裝 openssl。6.2 Prisma Client 生成產(chǎn)物的拷貝策略第二個(gè)坑是 Prisma Client 的生成產(chǎn)物沒(méi)有從 builder 完整拷貝到 runner。prisma/client 自身有一些運(yùn)行時(shí)依賴(lài)真正在運(yùn)行時(shí)要訪問(wèn)的包括 node_modules/.prisma/client 下的 query engine 二進(jìn)制以及 node_modules/prisma/client 下的主入口文件。最穩(wěn)妥的做法是不要在 runner 階段再次運(yùn)行 prisma generate因?yàn)槟切枰暾?prisma CLI 和 schema 文件會(huì)讓鏡像體積變大。而是把 builder 里已經(jīng)生產(chǎn)好的 node_modules/.prisma 整個(gè)目錄拷過(guò)來(lái)再把 prisma/client 也拷過(guò)來(lái)。具體拷貝邏輯可以簡(jiǎn)化成COPY --frombuilder /build/node_modules/.prisma ./node_modules/.prisma COPY --frombuilder /build/node_modules/prisma/client ./node_modules/prisma/client如果你不確定哪些目錄是必須的可以在 runner 階段直接安裝 prisma/client 后手動(dòng)跑一次 prisma generate雖然鏡像大一些但至少不會(huì)漏東西。生產(chǎn)環(huán)境我建議先把上面的拷貝方案跑通然后對(duì)比兩種方式產(chǎn)出的鏡像體積你會(huì)明顯感受到節(jié)省的那幾十 MB 空間。6.3 構(gòu)建緩存與鏡像瘦身技巧多階段構(gòu)建里有一個(gè)細(xì)節(jié)值得注意npm ci 和 npm run build 在 Docker 里是兩層不同的緩存塊。如果每次安裝依賴(lài)時(shí) package.json 都沒(méi)變Docker 會(huì)直接復(fù)用緩存不重新執(zhí)行 npm install。所以 Dockerfile 里 COPY package*.json 和 COPY src 分開(kāi)寫(xiě)是有意的源碼變更不會(huì)導(dǎo)致依賴(lài)重新安裝構(gòu)建速度快很多。還要注意鏡像里不要留下 .env 文件。生產(chǎn)環(huán)境的環(huán)境變量通過(guò) docker compose 或容器平臺(tái)的 secrets 機(jī)制注入而不是打進(jìn)鏡像。如果把 DATABASE_URL 是寫(xiě)死在 .env 里再 COPY 進(jìn)鏡像等于把數(shù)據(jù)庫(kù)密碼公開(kāi)給了所有能拉取鏡像的人。我在實(shí)際的 Dockerfile 里不會(huì) COPY .env而是在運(yùn)行時(shí)通過(guò)環(huán)境變量注入。這個(gè)習(xí)慣在多人協(xié)作的項(xiàng)目里尤其重要。NODE_ENVproduction 和 npm ci --omitdev 的組合也能去掉一大半 devDependencies。NestJS 的編譯依賴(lài)在 builder 階段已經(jīng)用掉了runner 階段只需要 nestjs/core、nestjs/common、prisma/client 這些運(yùn)行時(shí)依賴(lài)。7. 容器化開(kāi)發(fā)中的高頻報(bào)錯(cuò)與排查鏈路7.1 數(shù)據(jù)庫(kù)連接失敗完整的定位路徑這類(lèi)報(bào)錯(cuò)我用一套固定的排查鏈路能省下很多調(diào)試時(shí)間。先看容器狀態(tài)docker compose ps確認(rèn) postgres 和 app 都是 Up 狀態(tài)。如果 postgres 沒(méi)起來(lái)docker compose logs postgres 看日志多半是初始化失敗或數(shù)據(jù)卷權(quán)限問(wèn)題。然后看應(yīng)用日志docker compose logs app確認(rèn)報(bào)錯(cuò)碼是 P1001 還是 P1000。P1001 優(yōu)先檢查 DATABASE_URL 的主機(jī)名是不是 postgres服務(wù)名端口是不是 5432P1000 檢查用戶(hù)名密碼是否和 postgres 服務(wù)的環(huán)境變量一致。如果日志里報(bào)的不是 Prisma 錯(cuò)誤而是 ECONNREFUSED那就用 docker compose exec app 進(jìn)入容器跑 npx prisma db pull 等命令手動(dòng)觸發(fā)一次連接觀察錯(cuò)誤信息。很多次我以為問(wèn)題出在 Prisma 配置后來(lái)發(fā)現(xiàn)是 docker-compose.yml 里 postgres 服務(wù)沒(méi)有暴露端口到宿主機(jī)。開(kāi)發(fā)環(huán)境應(yīng)用容器和數(shù)據(jù)庫(kù)容器都在同一個(gè)自定義網(wǎng)絡(luò)里它們之間不需要通過(guò)宿主機(jī)端口通信但如果你在宿主機(jī)上直接跑本地應(yīng)用想去連 Docker 里的 Postgres就必須把 5432 端口映射出來(lái)。這個(gè)本地連容器、容器連容器的場(chǎng)景不同排查路徑也不同。7.2 文件監(jiān)聽(tīng)失效與 node_modules 權(quán)限問(wèn)題熱重載失效是一個(gè)特別會(huì)消磨耐心的坑。如果改完代碼容器沒(méi)有反應(yīng)優(yōu)先懷疑 watch 模式在跨文件系統(tǒng)場(chǎng)景下的監(jiān)聽(tīng)問(wèn)題。按第四章的方式配置 nest-cli.json 的 watchOptions 啟用輪詢(xún)絕大多數(shù)情況能解決。還有一種是權(quán)限問(wèn)題容器內(nèi)的 Node 進(jìn)程如果對(duì)源碼目錄沒(méi)有讀權(quán)限也會(huì)導(dǎo)致監(jiān)聽(tīng)不到文件變化。node_modules 相關(guān)的坑則表現(xiàn)為啟動(dòng)報(bào)錯(cuò) Module not found。這不一定是依賴(lài)沒(méi)裝上而是 bind mount 覆蓋了 node_modules。當(dāng)你把宿主機(jī)目錄整體掛載到容器里而沒(méi)有使用匿名卷隔離 node_modules 時(shí)容器內(nèi)的依賴(lài)會(huì)被宿主機(jī)的同名目錄遮住。檢查方法很簡(jiǎn)單docker compose exec app ls node_modules看看 nestjs/core 是否真的存在。7.3 端口沖突與啟動(dòng)路徑錯(cuò)誤端口沖突的報(bào)錯(cuò)看起來(lái)像 NestJS 啟動(dòng)時(shí) listen 失敗。常見(jiàn)原因是宿主機(jī)上的 3000 端口已經(jīng)被其他進(jìn)程占用或者在 docker-compose 里同時(shí)定義了多個(gè)服務(wù)占用了同一個(gè)端口。排查方式是把 ports 里的映射改成 3001:3000 試試如果能啟動(dòng)說(shuō)明是宿主機(jī)端口占用的鍋。不要為了調(diào)試去改 NestJS 的 listen 端口那樣容易和 compose 里的配置混淆。啟動(dòng)路徑錯(cuò)誤則發(fā)生在 Dockerfile 的 CMD 配置上。開(kāi)發(fā)鏡像跑 npm run start:dev 沒(méi)問(wèn)題但生產(chǎn)鏡像里如果 dist 目錄的路徑和 CMD 里寫(xiě)的路徑不一致會(huì)報(bào) Cannot find module .../dist/main.js。多階段構(gòu)建里尤其容易出這種問(wèn)題因?yàn)?builder 階段的 WORKDIR 是 /buildrunner 階段的 WORKDIR 是 /appCOPY 的路徑必須顯式寫(xiě)成 --frombuilder /build/dist ./dist。建議 production 階段啟動(dòng)后先用 ls dist 確認(rèn)產(chǎn)物存在再排查路徑。7.4 Prisma 引擎下載失敗與版本鎖定最后一個(gè)高頻問(wèn)題是 Prisma 引擎相關(guān)報(bào)錯(cuò)典型信息是 Prisma Client could not fetch the query engine. 原因是首次執(zhí)行 prisma generate 時(shí)需要從網(wǎng)絡(luò)下載引擎二進(jìn)制。在容器構(gòu)建環(huán)境中如果網(wǎng)絡(luò)受限或者需要配置代理下載就會(huì)失敗。最簡(jiǎn)單的處理方式是在 npm 安裝 prisma 時(shí)指定鏡像源或者把引擎二進(jìn)制提前緩存到構(gòu)建器里。Prisma 的版本組合也容易出問(wèn)題prisma CLI 和 prisma/client 的主版本必須一致。如果你用 npx prisma migrate 命令時(shí)看到類(lèi)似 Prisma CLI version mismatch 的提示先檢查 package.json 里這兩個(gè)包是不是同一個(gè)版本。團(tuán)隊(duì)協(xié)作時(shí)建議把 prisma 和 prisma/client 的版本精確鎖定不要用 ^ 或者 ~ 前綴避免某次依賴(lài)更新后開(kāi)發(fā)和生產(chǎn)環(huán)境的 Prisma 引擎不一致出現(xiàn)本地遷移成功、生產(chǎn)遷移失敗的怪現(xiàn)象。寫(xiě)在最后的實(shí)操建議整套 NestJS、Prisma、Docker 的組合跑通之后我最大的體會(huì)是先解決環(huán)境問(wèn)題再考慮性能優(yōu)化。很多人一上來(lái)就調(diào)連接池、搞鏡像多階段優(yōu)化結(jié)果最基本的容器網(wǎng)絡(luò)都沒(méi)通反而被各種報(bào)錯(cuò)帶偏了方向。我自己的順序永遠(yuǎn)是先 docker compose up 把數(shù)據(jù)庫(kù)和應(yīng)用都拉起來(lái)確認(rèn)接口能通再折騰熱重載最后才做生產(chǎn)鏡像的瘦身和部署優(yōu)化。另外schema.prisma 這種關(guān)鍵文件一定要納入代碼評(píng)審范圍它決定了數(shù)據(jù)庫(kù)結(jié)構(gòu)改起來(lái)不像普通代碼那樣可以隨意重構(gòu)。遷移文件提交到倉(cāng)庫(kù)后就不要手動(dòng)修改哪怕只是改個(gè)字段名也應(yīng)該通過(guò)新建遷移來(lái)完成。這個(gè)習(xí)慣能幫你避掉絕大多數(shù)數(shù)據(jù)庫(kù)結(jié)構(gòu)不一致的問(wèn)題。
返回列表
PREV
查看更多資訊
NEXT
返回資訊列表
97一本大道亚洲一区| 一区二区影视| 欧美不卡在线美女| 另类一区| 色呦呦呦在线观看视频| 91搡老女人老妇女老熟女歌词翻译| 极品少妇99| 五月综合色| 欧美性爱三区二区| 天天草夜夜草高潮片| 91亚洲人| 狠狠97| 麻豆性爱视频在线播放| 欧美性爱一区| 久久久久元码视频| 久久超碰亚洲人| 国产精品麻豆成人AV艾秋| 国语精品内射在线观看| 18禁中文字幕| 欧美日韩黄片精品在线| 秋霞网无码| 综合亚州欧美| 深喉吞精| 日本欧美不卡| 欧美牲| 中文字幕一区二区三区人妻不卡 | 高清肉丝中文无码| 九九九精品一区二区无码| 97色五月天完| 日韩另类色图| 欧美一区二区日韩传媒搭讪精品| 久视频在线观看| 综合五月天| 992这里有精品| 视频分类 国内精品| 亚欧视频在线| 日本激情免费大片| 亚洲精品美女久久久久久久久| 日韩丰满熟妇| 欧美在线播放aaaa| 蜜桃久久综合视频| 欧美久久婷| 91欧美另类| 啊啊啊不要啊啊受不了了视频在线| 色蜜AV| 调教熟妇 久久久久久| 日韩精品一区二区三区四虎影视| 大香蕉伊人色偷偷在线| 五十路熟女工口| 欧美日韩青操| 久久中文字幕在线观看| 超碰国产精品久| 国产精品人妻熟女aⅴ| 手机在线人成免费视频| 女人天堂AV五区在线| 亚洲AO在线| 欧美成人色| 激情欧美97| 又大又大又大又粗爽高潮观看| 欧美加勒比| 欧美综合网| 91在线超高颜值国产| 国产成年免费大片黄在线观看| 精品国产一区二区三区香蕉欧美 | 亚洲限制级| 九九免费影片| 377p欧洲日本亚洲大胆| 97av在线视频| 美国三级日本三级久久99| 天天操天天干美女网址导航| 豆花视频操逼网址| 丁香啪啪| 亚洲精品一区二区免费在线观看| 超碰97欧美| 亚洲av综合色区无码一| 亚州操操穴网| 欧美天天综合在线| 激情一区二区三区在线观看| 国产精品午夜精品| 人妻偷拍一区二区三区| 久久久久久久久久久久久久久乱码 | 日韩中文字幕2020| 9久热这里只有精品| 国产极品粉嫩馒头一线天av| 九九热男人天堂| 亚欧洲一区二区视频| 天堂综合网| 中文字幕aⅴ在线视频| 九九性视频| 性爱AV天堂| 1区2区3区视频| 唐山老熟妇露脸啪啪叫| 91亚州欧美| 好涩综合| 国产真实野战在线视频| 91中文精品日韩欧美在线 | 91丨豆花丨熟女| 九九毛片这里只有精品| 精品人妻15区| 熟妇操花| 91AV天美在线视频| 国产精品熟女乱伦| 精品人妻一区二区蜜桃视频| 日本日逼高清| 五十路熟女工口| 玖草在线视频| 亚洲一区深夜| 91网九色蝌蚪操熟女| 欧美性爱另类综合| 国产亚热在线久久| 亚洲无吗在线视频| 少妇人妻激情四射| 99久久久er直播网址| 嗯啊不要啊啊在线观看视频| 国产免费黄色一级大片| 久久国产视频专区一二三| 美欧色综合| 激情第四色| 欧美肥臀在线| 美女自卫慰黄网站免费| 啊啊啊啊,啊啊好多水 | 青青草这里只有精品| 亚洲激情av| 欧美情色亚洲| 久草男人天堂| 天天天天天天天天天天干美女| 东京热精品97综合网| 欧洲在线性爱视频| 五月天激情婷婷| 午夜爽爽爽在线观看永久入口姬片| 韩国一级做a久久久久| 九九这里只有精品| 欧美国产精品久久九九| 啊啊啊啊啊啊啊啊要喷了| 久久久亚洲高清不打码| 中文欧丝袜诱惑| 国产欧美岛国精品一区 | 尤物网站91| 日本人体九九九九九九| 熟女五十路一区二区三| 精品熟妇视频一区二区| 日韩一区二区精品视频| 日本孕妇一区二区视频操逼免费看 | 看免费的黄片| 亚洲精品不卡一二三区| 国产激情片在线观看| 天天干人人乐| 草伊人高潮喷水超碰| 国产精品自拍xxxx| 啊啊啊啊好爽好舒服一区二区易域| 欧美激情总合网| 大屁股人妻女教师撅着屁股| 91美女视频电影| 九九色婷婷| 久久久久九九九九| 人人摸人人舔一区二区| 2019AV天堂| 另类一区| 亚洲一级性爱视频免费看| 欧美丝袜亚洲| 亚洲一区二区三区麻豆传媒| 激情五月天丁香社区| 男人天堂网站| 91精品婷婷国产综合久久| 日韩在线视频1234| 欧美日韩 强奸乱伦| 嗯嗯不要视频| 中国熟女91| 天综合网| 亚洲国产第一页综合视频| 色综合久久av| 九七超碰| 9久在线视频只有精品| 在线亚洲丝袜视频网站| 狼人综合婷婷激情四射 | 色小视频蜜乳| 久久久久亚洲AV无码专区少妇| 蜜汁欧美| 黄色av播放免不| 99re9这里只有精品| AV 少妇 人妻 偷拍| 欧美日韩性爱操大逼| 2017亚洲天堂| 久久精品国产亚洲av水密被窝| www被窝色com| 久久綜合很很很| 亚洲午夜免费狠狠干| 人妻中文字幕日韩电影| 久久黄色视频一区二区三区| 国产肏逼网站| 另类天堂| 亚洲 小说 欧美 激情 另类| 超碰九7免费| 亚州五月| 欧美肥臀在线| 9精品久久久久| 美日韩一二三区| 国产原创精品| 国产精品久久9| 嗯啊不要在线| 久久久久骚| 天天摸,夜夜摸| 丁香激情网| 色五月综合| 久久精品国产免费观看99| 无码精品一区二区三区潘金莲| 日本在线观看网址| 久久超碰国产一区二区三区| 91碰超| 亚洲,日韩,欧美,成人播放| 在线观看中文字幕| 国产精品香蕉| 亚洲欧美国产中文视频| 四虎国产精品永久在线囯在线| 欧美美女视频| 91综合色噜噜| 欧美午夜视频精品久久| 色色国产| 日韩中文字幕2020| 2019男人的天堂| 天天综合91入口| 麻豆一区二区AV天美| 东北老熟女| 人妻天堂三区| 玖玖爱在线视频免费观看| 91久久九九精品国产综合| 一区AV| 香伊人在线| 欧美综合娱乐久久| 人人透人人操| 99热99re6国产在线播放| 淫骚熟女一区二区三区| 天天爽入口| 亚洲在线a| 九九AV| 欧洲欧美视频一区二区| 九九黄色视频在线观看| 9久综合网| 性性欧美| 中文字幕欧美丝袜07资源| 日韩欧美亚洲自拍偷拍| 黄网色一区二区三区四区精品| 国产乱伦性爱AV| www.狠狠干.coom| 欧美论理片| 97爱爱爱| 免费久久精品麻豆一区二区av| 欧洲无码一区二区| julia ann久久| 999综合网| 又大又长又粗又爽又黄| 亚洲宅男天堂| 亚洲综合图片在线| 老女人综合网| 免费强奸av| 91精品电影18| 日韩91网| 国产精品成人蜜臀AV在线| 丁香五月性| 欧美色图中文字幕| 极品出轨视频网站| 啪啪AV导航| 夜夜中出国产| 九九九不卡| 国产精品久久久久久久AV大片| www久久久| 情色五月天久久久| av一区二区三区不卡| 五月丁香影院| 女人天堂网| 伦激情人妻另类人妻| 丁香婷婷久久| 欧美色九九| 强奸乱伦大香蕉| 日本天天吊| 欧美精品不卡一二三四在线91| 日本性感人妻91| av资源在线播放天堂| 神马久久久久久久久久久久| 性综合网| 白嫩嫩一区| 日日不卡av| 亚洲高清无码在线桃色| AV99热18这里只有精品| 美国精品国产精品| 青草香蕉网| 玖玖爱影院| 午夜色婷婷| 夫妻AV网站| 日韩午夜精品一区二区三区电影| 国产久久一区二区| 97超碰资源网| 色色色日本| 东北夫妻性偷拍| 精品999一区二区| 激情五月天色色| 亚洲亚洲亚洲天堂天堂| 国产久久久久久久久一区二区 | 亚乱色| 97超碰免费生活| 啪一啪免费视频| 青青操视频在线| 久久亚洲AV成人精品无码| 亚洲熟女一区| 少妇干B| 97在线资源| 91呆哥人妻| 日曰骚久久精品| 亚洲精品久久久久久久蜜桃臀| 日日摸日日弄日日拍| 久久男女激情视频网站 | 激情综合五月婷婷| 大二网站亚洲| 97精品在线| 婷婷亚洲五月***久久| 男人天堂网手机版婷婷| 91狠狠色丁香婷婷综合久久| 欧美一级A一级a爱片久久| 91色女| 成人无遮挡毛片免费看| 日韩丨制服丨中文|在线| 日韩一级成人毛片免费观看| 天美麻豆一区二区三区| julia在线观看久久| 婷婷在线视频在线观看| 综合激情一一91| 无遮挡猛进视频免费无限观看| 精品美女少妇一区二区| 免费看污网站| 亚洲操人| 无码直播久久久| 一二视频神马久久传媒| 午夜男人天堂| 亚洲五月婷| 91在线视频国产网站| 亚州色图片在线色| 欧美性战999| 蜜乳AV色欲AVAV无码| 欧美99999| 亚洲清纯唯美| 亚洲视频小说| 亚洲色图超碰在线| 国产精品三级视频网站| 国产精品视频自拍在线| 91天堂网| 精品国产乱码久久久久久日本公司| 日韩偷拍色图| 欧美黄片视频在线观看免费 | 97人人干人人操| www.久久制服糖| 久久久久久九| 欧美伦乱| 欧美日韩亚洲少妇寂寞影院正在播放| 操我啊啊啊啊啊| 9l视频自拍9l九色成人| 18禁美女裸体无遮挡啪啪| 狠狠爱综合网| 五十路一区无码| 在线洲亚线| 日本天天干天天搞一区| 国产五码丝袜屁眼| 天天插夜夜爽| 大香蕉男人的天堂| 中文字幕天天操| 亚洲AV无码| 超碰人妻在线| 亚洲av无码成人精品国产| 中文字幕一区二区日韩网| 精品人妻一区二区三区在线视频不卡| 91激情国产| 中文在线视频| 午夜精品人妻二区三区| 老司机久久| 91亚洲欧美色图| 久久久久久久久久久久久久9999| 亚洲黑丝在线| 亚洲熟妇丝袜在线观看| 色av中文字| 欧美一区91大爱| 大香蕉操久久| 偷拍网站久久男女男| 天天爽爽爽爽| 精品国产网站| 亚洲综合小视频小说在线观看| julia在线观看久久| 亚洲激情网一二三四区| 亚洲国产欧美日韩精品一区二区三区,国产一区二区三区在线看片,欧美性猛交 XXX | 性爱av在线免费观看| 亚洲高清无码AAA久久久精品| 国产精品干干干| 久久这里是精品| 园内精品自拍视频在线播放| 爱av免费| 97亚洲综合电影| 午夜久久一区二区无码中出| 日本蜜桃| 亚洲图片小说欧洲| 久草午夜| 97在线精品观看视频| 多毛小伙内射老太婆| 最新日产中文在线麻豆| 口爆综合网| 97精品视频免费| 91日产欧美| 亚洲欧美91√| 97超碰超碰| 中文字幕国产| 色五月网址| GVH-003 母子姦 青木玲-麻豆视频,麻豆视传媒短视频网站入口,麻豆视传媒官网直 | 加勒比久久av| 老妇女91| 国产av又色又爽又黄| 亚洲国产一区二区三区四区国产| 欧美视频在线第3页| 夜夜狼人妻| 中文子幕一二三| 久久精品无码专区| 国产99精品一区二区三区免费| 亚洲aV性爱| 在线啊啊啊啊| 久久久天美| 欧美夜夜草视频| 一区二区三区精品视频| 久久內射| 国产精品白丝| 影音先锋国产精品| 青草香蕉网| 精品日韩产品在线,日韩在线不卡视频,欧美日韩免费专区/久, | 亚洲精品官网在线观看| 大香蕉婷婷| 999九九精品| 国产400孕妇孕交群| 中文字幕国产| 一区=区三区视频| 天天综合~91| 97资源视频| 98一区二区精品| wuyechaopeng| 国产一级内射无挡观看| 欧美精品四区| 密臀成人视频久久久| 在线有码中文字幕| 亚洲情色五月天 | 中文字幕一二三av| 秋霞久久亚洲精品成人| 亚洲图片欧美制度| 久操精品| 97天天摸天天碰| 蜜臀99久久精品| 日日噜噜夜夜狠狠视频无| 亚洲……91| 99re黄| 久久这里只精品99re66图| 丝袜天堂| 国产av激情无码久久天堂| 91在线|亚| 国语精品av| 国产精品无码论坛| 大屁股熟女一区二区三区| 亚洲 欧美 制服 另类 自拍| 青青青操| 日本性交操一区二区不卡系列| 亚洲性爱高潮影院| 99无码狠狠久久| 亚洲日韩AV视色| 超碰97COm中文| 超碰99在线观看| 国产又粗又长视频| 亚洲 欧美 中文 日韩超碰| 欧美—性—交—色| 欧美色婷婷| 97久久超碰日韩精品| 国产亚洲在线观看| 男人天堂网址 | 亚洲性爱成人| 久久精9| 综合 欧美 亚洲 日本| 亚洲男人天堂2016| japan日本高清乱xxxx| 加勒比东京热五月天天堂网| 日本一区二区三区四区免费观看| 久男人久久| 超碰人妻在线| 成人国产视频在线观看| 狠综合网| 久久精品亚洲成a人天堂| 蜜桃臀一区二区aV| 久久国色天香香蕉| 国产乱伦亚洲| 无码精品啪啪啪一区二区三区三州| 黄色高清无码无码破解免费暗网 | 九九无码| 亚洲图片色图欧美另类| 97在线欧| AND人妻系列| 精品中文字幕第一页| 欲色啪| 一区二区三区精品黑丝白丝酒店对鸡 | 亚洲se91| 福利在线视频一区二区| 婷婷亚洲天堂| 无码区蜜乳| 蜜桃视频啊啊啊啊| 丝袜内射| 国产免费永久精品无码| 强被迫伦姧在线观看无码网站| 亚州色图片在线色| AV中文在线可看| 超碰国产精品久| 91情色在线| 超碰97最新人妻| 五月天精品| 人人操人人摸人人看人人插| 婷婷8月天青娱乐| 妇女视频网站| 天天影视色香色欲| 秋霞欧美性爰视频| 成人自拍三级在线观看| 欧美色图91| 强奸乱伦Av网| 五月天AV资源| 好吊色一区| 人妻AV在线| 国产高清26uuu| 97干在线| 91老司机视频| 亚洲蜜臀视频精品久久| 乱人伦 国语对白:视频直接看| 日韩欧美大力操| 久久东京热久久| 欧美性Fer办公室秘书| 熟妇亚洲一区二区三区| 这里有精品| 99久久久无码国产精品性男| 狠狠操官网| 黄片www视频免费| 国产精品另类| 亚洲有薄码区久久在线一区| 99只有精品| 精品人妻一区二区三区-国产精品 一个人在线看的黄色电影网站 | 日本二区不卡| 狠狠爱AV| 亚洲日韩XXX| 久久精品老司| 操B久久| 亚洲熟妇乱女区二区三区| 99日韩| 国产激情片在线观看| 99久久婷婷丁香| 可以免费看黄片的视频| 韩国三级一线观看久| 色五月av| 国产农村妇女精品| 狠狠超| 啊啊啊啊啊啊啊啊视频| 美女久久久| 丰满人妻区一区二区三| 2021国产成人精品久久| 人人弄人人摸| 亚洲日本激情| 视频黄色国产一级| 国产精品一区二区三区,亚洲综合| 影音先锋新男人| 9丨亚洲一区二区在线| 久久久久久亚洲Av无码| 影音先锋视频在线| 国产尤物AV尤物在线观看不卡| 爽极品影院| 一牛影视成人片免费| 亚洲va有码在线天堂| 日韩国产成人自拍视频| 欧美99热| 色性荡荡荡荡视频| 亚洲色图国产另类| 在线电影亚洲色图| 人爽不卡视频| 一二三四视频中文字幕在线看| 欧美日韩色综合网| 不卡啪啪视频| 97超级久久强资源| 极品粉嫩少妇视频| 爱丝福利| 放黄片放3级黄片没穿衣服| 国产精品日本无码A片| 亚洲精品毛片在线观看| 亚洲四虎熟女精品| 99久久这里只有精品| 久久久久9999妇女| 18精品一二区| 国产精品国产亚洲区艳妇糸列| 强奸乱伦亚洲第一页| 国产日韩欧美三级片| 99超碰色| 91欧美巨乳| 亚洲美女av无码| 久久亚洲AV成人精品无码| 五月婷婷五月天| 日日橹狠狠爱欧美超碰| 午夜亚洲| 手机在线A片| 青青草中文-久久青草精品一区二区三| 无码一区二区三区四区五区六区七区八区九区十区视频 | 中美日韩毛片| 久久男人| 97精品熟女少妇一区| 91狠狠色丁香婷婷综合久久| 91综合国产精品| 亚洲女人91| 国产日韩欧美亚洲精品95| 天天综合,91综合永久| 色阁阁AV综合网| 色欲天天综合久久久无码网中文| 免费看欧美美女黄色大片| 中文字幕天天天天天| 婷婷10月天青娱乐| 美女尤物人人操| 精品国产自在在线99| 欧美色吧综合| 亚洲人妻中文高清| 欧美熟妇操操视频| 2017大香蕉| 欧美一级色| 破处bbq| AV和黑人在线播放| 99啪啪| 亚洲春色一区二区三区| 久久思思热| 一区e区三| 日韩乱中文| 亚州久久9| 色色色日本| 澳门人妻久久| 男人的天堂 在线一区| 婷婷五月天社区| 色九色久| 91热爆在线| 91操熟女视频| 日韩啪啪网| 婷婷10月天青娱乐| 久综合网| 久久中文字幕在线观看| 色情成人五月天| 99re28在线观看| 欧美性爱五月天| 欧美高清91| 九九99久久| 熟妇女伦乱视频| 久久久蜜桃一区二区三区| 久久久不卡| 天天看天天综合成人网| 欧美性爽xyxOOOO| av操操不卡| 草莓精品视频在线免费观看| 亚洲欧美setu| av无码av无码专区| 久久久精| 婷婷色在线| 精品免费一区| 国产美脚女优尤物在线观看| 97人人夜夜精品视频| 亚洲色入欧美| 日本性爱少妇| 熟妇视频一区二区三区在线| 老熟女91av| 不卡av在线中文字幕| 国产亚洲精品美女| 激情接吻视频久久久久久| 伊人性在线视频| 激激五月| 天天操夜夜操狠很操| 青草园大香蕉| 蜜桃臀av在线观看| 免费αV在线视频| 久久6热精品99视频| 国产又色又爽又舒服的三级视频| 国产深喉视频一区二区| 色九九九九| 曰韩av中文字幕专区| 色婷婷一区二区三区久久| 久久中出在线| 97av在线视频| 国产亚洲精品A在线观看下载| 中文字幕久久亚州无码| 国产激情久久久| 国产兽交视频在线播放| 人妻人久久精品中文字幕| 精品少妇一区二区三区免费观看| 久久午夜鲁丝片| 97 国产精品| 美女的肌被草喷水视频| 日韩一级片在线看| jizz啪啪| 一区二区三区一亚洲中文字幕、综合区灬 | 北野未奈加勒比av| 亚洲国产欧美日韩精品一区二区三区,国产一区二区三区在线看片,欧美性猛交 XXX | 日韩在线观看AV| 国产性刺激| 免费一级视频特黄色大片| 久久超碰国产一区二区三区| 午夜九九| 国产精品久久久久久久久久久久久久久久久久 | 不卡免费av在线播放| 亚洲欧美国产中文视频| 怡春院久久| 亚洲天堂日本| 麻豆乱码久久精| 香蕉综合网| 国产福利av精彩对白| 亚洲国产成人7777| 俞拍久久国应视频| 久久久久久免费电影| 欧美色图成人网一区二区 | 日韩午夜国产| 狼人综合婷婷激情四射 | 日本一级一级一级一级| 中国一区二区亚洲人妻| 豆花视频操逼网址| 久久男人天堂| 爱逼综合| 美欧色综合| 大茄子熟女AV导航| 亚洲图片偷拍欧美| 久久精品99久久久久久| 美女91在线观看| 91扒丝袜综合在线| 九九毛片这里只有精品| 天天日夜夜爽| 久久99久久99精品免视看婷婷| 日本一区二区做爱的视频| 另类小说综合网| 亚洲男人综合| 91性高朝久久久久久久久| 久操视频在线观看| 好色综合| 超碰精品日韩欧美国产| 亚洲福利影院一区久久| 欧美天天射| 亚州91| 蜜臀99久久精品久久久懂爱| 少妇一区二区三区| 99re免费| 人人操 欧美| 伊人黄色片| 91在线超高颜值国产| 久综合国内精品自在自线| 国产视频一区二区三区在线免费观看| 日韩极品无码B| 欧美激情另类一区二区| 日欧亚洲二三区大片不卡| 日韩一级特黄av毛片| 国产精品久久久久久久毛片1| 高清无码 国产精品| 性做久久久久久久| 99热网站| 亚洲精品一二三四区| 加勒比AV网| 91久久国产精品| 亚洲色人| 波多野结衣一级视频| 久热香蕉精品在线视频| 成人午夜无码视频| 超碰 97国产熟女| 久久国产精品,久久国产| 亚洲www91| 熟女91网| 综合久久97| 可以在线观看的黄色网址| 播播亚洲小说亚洲| 熟女人妻av在线资源,黄色的资源| 九九热男人天堂| 制服中出中文人人精品| 理论久久婷婷网8| 色吧 综合| 无码精品人妻一区二区三区妖精| 天天操天天舔| 9久久9综合| 伊人在线大香蕉视频久久| 欧美日韩久久精品爱爱| 国产又黄又粗的视频| 国产精品久久久久综合| 爆乳免费黄网站| 熟妇激情| 视频国产欧美在线播放| 欧美系列在线一区二区| 夜夜中出国产| 1024午夜激情男人的天堂| 色爱亚洲| 国产传媒操逼视频| 国产欧美第五页| 夜夜青青无码影院| 欧美精品69性爱| 综合色色网| 男人天堂综合| 91丝袜在线观看| 一区二区三区激情在线观看| 午夜福利久久久噜久噜久久综合| 羞答答AV中文字| 天天干天天舔| 女优免费一区二区永久| 精品人妻一二三四区视频| 91夜色| 99色天堂| 美女爽爽爽刺痛洞洞| 日韩免费簧片| 国产欧美日韩在线观看麻豆传媒公司| 亚洲色图欧美色图制服诱惑| 国产主播福利| 人妻激情另类| 好湿好紧视频| 伊人久操| 精国久久一区二区三区98| 69视频入口| 亚洲精品 大香蕉| 日韩欧美~中文字| 操逼国产免费| 人人澡综合涩| 国产在线综合网| 国产精品一区二区三区在线密挑| 国产97在线播放| 约操熟妇| 精品人妻无码一区二区三区不卡-精品人妻无码一区二区...|精品少妇一区二区三 | 亚洲少妇综合在线播放| 大香蕉99热| 国产精品国产亚洲区艳妇糸列| 久久久久久亚洲精品不卡人乳| 久久久久深夜无码| 天堂8在线新版官网| A一级色女| 亚洲精品官网在线观看| 伊人久久亚洲中文字幕不卡| AA级电影三区| 久久久性爱视频| 国产三级资源在线观看| 欧美婷婷久久| 色欲无码人妻日韩欧美精品| 欧亚日韩三区| 国产精品69人妻无码久久久| 亚洲天堂日本| 中日韩欧美精品无码AⅤ一区二区| 中文字幕、久久精品国产2020、久久综合久久自在自线精品自、亚洲 | 天天看夜夜看日日干| 欧美最婬乱婬爆婬性视频 | 国产精品熟女AV中文字幕在线播放| 国产剧情在线| 亚洲天堂性爱| 色综合V| 亚洲男人的天堂网| 日本一区二区不卡精品| 爱丝福利| 天天综合网站| 久久久久久久强迫| 999综合色| 中国探花熟女| 国产99热| 性生活久久久久久久久久| 亚洲欧洲综合av在线| 综合网亚洲| 97 亚洲 日韩 欧美 在线| 五月丁香黄色网| 天天天天天天天天综合| 一区二区三区 日韩欧美| 日日97| 欧洲中文字幕| japan日本高清乱xxxx| 亚洲做性| 欧美综合第一| 天天做日日爱夜夜爽| 久午视频| 人妻少妇色综合| 久久人人看| 国产精品成人AV片免费看网站| 亚洲 欧美 另类 日韩 人妻一区| 91精品无码人妻系列| 精品无吗m| 97超碰久| 六月婷婷激情| 婷婷丁香九月| 夜夜爽夜夜操| 99re99视频在线免费观看| 蜜乳av首页| 亚洲春色欧美激情自拍| 亚洲精品国产熟女久久久| 欧美性猛交美女自慰91| 五月婷网站| 欧美美女视频| 超碰日韩美妻| 欧亚洲精品有视频| 久草国产在线视频| 欧美天天综合网| 欧美激情精品久久久| 久久的网站啊啊啊啊啊| 在线99热| 色综合天天| 综合久久97| 97国产精选| 成人久久精品| 久久久9品一区二区三区| 黑人黄片在线免费观看| 黄色免费一级在线毛片| 欧美精品系列| 免费亚洲国产精品久久一区| 91色女| 91 刺激在线| 黄色欧美性爱视频| 少妇一级婬片免费放一级a性色.| 啪啪自拍九九综合| 亚洲中文字幕一区| 97超碰资源网| 久久久穴999| 精精夜夜| 亚洲91极品| 久99| 色情综合| 国产在线视视频有精品| jk白丝没脱就开始啪啪| 亚洲欧美成人网站AAA| 人妻91少妇| 欧美色交| 天天综合,91入口| 伦理日韩国产久久| 中文字幕人乱码中文字的预防方法 | 在现视频女上位好爽| 中文字幕在线日亚州9| 自拍偷拍 日韩无码| 中文字幕奈奈美被公侵犯| 自拍内地三级在线观看| 91综合色噜噜| 欧美男人天堂| 麻豆久久精品亚洲精品88| 欧美在线天堂| 91少妇人妻| 色欧美综合| 久操精品| 天天看夜夜看日日干| 欧美国产精品久久九九| 亚洲美女AV无码| 亚洲欧美色图| 亚洲欧洲成人在线电影| 免费A片三p视频| 爱妃国产亚洲视频中文字幕| 亚欧高清| 啪啪视频亚洲第一| 26uuu性物| 老司机射| 五月丁香综合啪啪| 中文字幕五区| 18一区二区三区| 久草资源在线视频官方总站日韩丝袜美腿 | 97干日韩| 中文97国产| 人妻丝袜肏逼| 热G综合热G中文| 青青久久艹| 国产成人亚洲精品无码最新在线| 岛国1区2区3区在线观看| 波多野结衣一级视频| 亚洲中文日韩欧美大香蕉视频| 日韩一级片在线看| 五月天综合网| 97超碰天天爱天天爱| 亚洲欧洲色情高清| 久久人妻一区二区三区高清| 色欲天香天天综合网-成年人三级片网站-欧美乱妇狂野-日韩国产专区-久久久久久 | 中亚黄色三级大片| 久久伊人东京热| 欧美黄页| 亚洲精品无码成人久久久99| 婷婷五月天久久久| 99久久无色码| 亚洲鸥美色图| 天久久久噜噜噜久久国产精品爽爽 | 乱伦图av| 99这里都是精品| AV丝袜少妇| 丝袜美腿91| 亚洲āv网址在线观看| 色yeye成人免费视频| 99色色网| av72网| 超碰人妻97| 无码高清国产AV| 五月婷丁香| 97一区二压| 狠狠爱大香蕉| 亚洲高清无码在线桃色| 日本精品一区三区| 五月开心久久AV官网| 久久久久久九九九| blacked精品一区国产| 亚洲一区深夜| 天天情欲宗合网| 中国AAAAAA黄色片| www色婷婷| 日韩无码AB| 国产精品女aA片爽爽视频| 自慰白浆在线观看| 日韩钢筋无码高清啾啾啾| 98超碰欧美| 99久久e免费热视| 久久伊人网视频一区二区三区| 91精品国| 老熟妇一区二区三区…| 成人影 天天操 亚洲| 亚洲丝袜二区在线| 黄片免费看的| 久久超碰免费的| 啪啪啪综合网| 激情丁香五月| 精品国产乱码久久久影院| 亚洲综合另类小说色区亚洲成av人片在www | 97久久久精品| 欧美不卡五十路| 青青操青娱乐| 有码专区最新中文字幕有码| 人人操人人搞人人草| 天天日日日射| 97爱综合| 亚洲91少妇| 超碰97COm中文| 91|九色|国产熟女| 99热国产精品| 欧美日韩国产高清在线一二三区| 久久97资源 网| AAAA欧美日韩| 久热久一区二区三区| 亚洲高清综合网| 亚洲日韩精品在线播放| 青青草日韩免费观看高清在线| 色欲av一区二区三区蜜芽| 国产一区麻豆免费观看| 欧美日本成人一区二区| 精品妇女一区二区三区| 九九九九精品九九九九| 少妇一线天久久久久久| 亚洲人综合19| 夜夜一区二区| 神马九九| 国产日韩精品一区二区三区| 国产色产精品在线观看| 精品99999久久久久久| 91狠狠综合| 亚洲91色在线| 99老司机精品视频在线观看| 91欧美美女日韩国产婷婷| 素人一区二区三区日韩| 最新中文字幕av| 2019久久久久久久久福利| 天天干天天中出av| 国产探花精品在线| 曰本道人妻久久久在线不卡色视频| 亚洲国产高清福利视频| 日日爽熟女| 久久精品人体AV| 久久性爱视频免费看| 熟女欧美日韩综合婷婷| av在线一区二区三区| 色踪合AV| 婷婷在线视频| 2023天天操夜夜操| 另类 综合 日韩 欧美 亚洲| 日本视频在线观看污污污| 我爱操| 97干在线看| 亚洲精品无码成人久久久99| 国产精品69久久久久久久| 91无码中出人妻视频| 国产精品爆乳懂色蜜乳| 日本最新免费韩国1区2区视频播放| 国产操逼逼网| 射综合网| 久久国99999| 探花精品视频| 伊人热综合| 精品人妻伦一区二区三区久久| 91久久久久久久| 五月天我淫我色av| 9.1小视频| 色月天AV导航| 黑人黄片在线免费观看| 99久久久无码国产精品性啊聊| 人妻内射一区二区在线视频| 亚洲人人操| 啪啪视频亚洲第一| 精品九区| 中文字幕女同在线| 婷婷五月天激情网| 国产野战露脸在线播放| 久久久久久久| 情色五月天网| 97超碰色五月| 欧美十八禁网站| 小说区 图片区色 综合区| 欧美色图小说综合 | 99re国产精品视频| 久久超碰97| 精品久操| 操死我了嗯嗯嗯| 日本特黄f c2| 日韩精品亚洲专区在线影视| 国产偷拍网站| 亚洲少妇视频| 超碰伊人在线| 青青操少妇| 久久,精品一二三| 久久久久国产精品喷潮免费观看臀| 一区二区乱码福利| 久久亚洲一区女同性恋中文字幕| 色五月第四色| 91超碰人人| 色婷婷久久| 欧美性爱一级操| 亚洲欧洲综合av在线| 搡老女人老91妇女老熟女| 新91视频.cmp| 色综合99999| 国产专区路线| 久久婷婷色综合一区二区三区| 无套内射性感少妇视频| 18禁网站在线播放| 91东京热男人的天堂| 大香蕉78| 超碰人妻久久| 亚洲深夜福利| 狠狠色五月亚洲91| 乱色老一区二区三区的观看方式| 黄色十八禁网站| 久久久久中出| 中文字幕一区 二区三四五 区日 日骚 | 韩国女主播青草福利视频| 国产激情综合五月久久| 无遮挡h肉动漫在线观看| 日韩乱伦影音先锋| 日韩中文字幕人妻视频| 欧美日韩国产另类综合| 久久性爱视频免费看| 国产强奸无码乱伦| 久久69| 国产精品白丝| 91性色| 超碰在线人妻中文字幕| 无码精品久久久久久亚洲| 国产性爱强奸乱伦大全| 欧美少妇色图| 狠狠操狠狠操操| 日韩三级伊人| 黑人美精品 A片| 97亚洲综合电影| 久久久999日本大片| 日韩精品国产精品五码一区二区| 九九99精品视频在线观看| 97综合在线| 人妻少妇一区二区| 日韩女优中文字幕| 欧美中文字幕一区 | 热久久无毒不卡| 欧美淫乱视频| 久久久久白虎| 91超碰在线| 国产亚洲性生活视频播放| 操逼逼中文字幕|