[{"data":1,"prerenderedAt":373},["ShallowReactive",2],{"i-lucide:languages":3,"i-lucide:chevron-down":8,"i-lucide:moon":10,"i-lucide:menu":12,"i-lucide:mail":14,"i-lucide:github":16,"i-lucide:linkedin":19,"blog-\u002Fblog\u002Fdockeriser-nestjs":21,"i-lucide:arrow-left":371},{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":7},0,24,false,"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"m5 8l6 6m-7 0l6-6l2-3M2 5h12M7 2h1m14 20l-5-10l-5 10m2-4h6\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":9},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"m6 9l6 6l6-6\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":11},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M20.985 12.486a9 9 0 1 1-9.473-9.472c.405-.022.617.46.402.803a6 6 0 0 0 8.268 8.268c.344-.215.825-.004.803.401\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":13},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M4 5h16M4 12h16M4 19h16\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":15},"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Cpath d=\"m22 7l-8.991 5.727a2 2 0 0 1-2.009 0L2 7\"\u002F>\u003Crect width=\"20\" height=\"16\" x=\"2\" y=\"4\" rx=\"2\"\u002F>\u003C\u002Fg>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":17,"hidden":18},"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Cpath d=\"M15 22v-4a4.8 4.8 0 0 0-1-3.5c3 0 6-2 6-5.5c.08-1.25-.27-2.48-1-3.5c.28-1.15.28-2.35 0-3.5c0 0-1 0-3 1.5c-2.64-.5-5.36-.5-8 0C6 2 5 2 5 2c-.3 1.15-.3 2.35 0 3.5A5.4 5.4 0 0 0 4 9c0 3.5 3 5.5 6 5.5c-.39.49-.68 1.05-.85 1.65S8.93 17.38 9 18v4\"\u002F>\u003Cpath d=\"M9 18c-4.51 2-5-2-7-2\"\u002F>\u003C\u002Fg>",true,{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":20,"hidden":18},"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Cpath d=\"M16 8a6 6 0 0 1 6 6v7h-4v-7a2 2 0 0 0-2-2a2 2 0 0 0-2 2v7h-4v-7a6 6 0 0 1 6-6M2 9h4v12H2z\"\u002F>\u003Ccircle cx=\"4\" cy=\"4\" r=\"2\"\u002F>\u003C\u002Fg>",{"id":22,"title":23,"body":24,"category":356,"date":357,"description":358,"draft":6,"extension":359,"image":360,"meta":361,"navigation":18,"path":362,"seo":363,"stem":364,"tags":365,"updated":369,"__hash__":370},"blog_fr\u002Fblog\u002Fdockeriser-nestjs.md","Dockeriser une application NestJS : guide complet",{"type":25,"value":26,"toc":350},"minimark",[27,50,55,58,231,237,241,287,291,307,311,339,346],[28,29,30,31,35,36,43,44,49],"p",{},"Dans mes missions freelance, je containerise systématiquement les applications. Voici la méthode que j'applique pour une API ",[32,33,34],"strong",{},"NestJS",", avec un build optimisé et un déploiement fiable. Cette démarche suit les ",[37,38,42],"a",{"href":39,"rel":40},"https:\u002F\u002Fdocs.docker.com\u002Fbuild\u002Fbuilding\u002Fmulti-stage\u002F",[41],"nofollow","recommandations officielles de Docker sur les builds multi-stage"," et la ",[37,45,48],{"href":46,"rel":47},"https:\u002F\u002Fdocs.nestjs.com\u002F",[41],"documentation de NestJS",".",[51,52,54],"h2",{"id":53},"le-dockerfile-multi-stage","Le Dockerfile multi-stage",[28,56,57],{},"L'idée : séparer le build de l'exécution pour réduire drastiquement la taille de l'image finale.",[59,60,65],"pre",{"className":61,"code":62,"language":63,"meta":64,"style":64},"language-dockerfile shiki shiki-themes github-dark github-dark","# Stage 1 — build\nFROM node:22-alpine AS builder\nWORKDIR \u002Fapp\nCOPY package*.json .\u002F\nRUN npm ci\nCOPY . .\nRUN npm run build\n\n# Stage 2 — production\nFROM node:22-alpine AS runner\nWORKDIR \u002Fapp\nENV NODE_ENV=production\nCOPY --from=builder \u002Fapp\u002Fnode_modules .\u002Fnode_modules\nCOPY --from=builder \u002Fapp\u002Fdist .\u002Fdist\nCOPY package*.json .\u002F\nEXPOSE 3000\nCMD [\"node\", \"dist\u002Fmain.js\"]\n","dockerfile","",[66,67,68,77,94,103,112,121,129,137,143,149,161,168,177,185,193,200,209],"code",{"__ignoreMap":64},[69,70,73],"span",{"class":71,"line":72},"line",1,[69,74,76],{"class":75},"sJ8bj","# Stage 1 — build\n",[69,78,80,84,88,91],{"class":71,"line":79},2,[69,81,83],{"class":82},"sOPea","FROM",[69,85,87],{"class":86},"suv1-"," node:22-alpine ",[69,89,90],{"class":82},"AS",[69,92,93],{"class":86}," builder\n",[69,95,97,100],{"class":71,"line":96},3,[69,98,99],{"class":82},"WORKDIR",[69,101,102],{"class":86}," \u002Fapp\n",[69,104,106,109],{"class":71,"line":105},4,[69,107,108],{"class":82},"COPY",[69,110,111],{"class":86}," package*.json .\u002F\n",[69,113,115,118],{"class":71,"line":114},5,[69,116,117],{"class":82},"RUN",[69,119,120],{"class":86}," npm ci\n",[69,122,124,126],{"class":71,"line":123},6,[69,125,108],{"class":82},[69,127,128],{"class":86}," . .\n",[69,130,132,134],{"class":71,"line":131},7,[69,133,117],{"class":82},[69,135,136],{"class":86}," npm run build\n",[69,138,140],{"class":71,"line":139},8,[69,141,142],{"emptyLinePlaceholder":18},"\n",[69,144,146],{"class":71,"line":145},9,[69,147,148],{"class":75},"# Stage 2 — production\n",[69,150,152,154,156,158],{"class":71,"line":151},10,[69,153,83],{"class":82},[69,155,87],{"class":86},[69,157,90],{"class":82},[69,159,160],{"class":86}," runner\n",[69,162,164,166],{"class":71,"line":163},11,[69,165,99],{"class":82},[69,167,102],{"class":86},[69,169,171,174],{"class":71,"line":170},12,[69,172,173],{"class":82},"ENV",[69,175,176],{"class":86}," NODE_ENV=production\n",[69,178,180,182],{"class":71,"line":179},13,[69,181,108],{"class":82},[69,183,184],{"class":86}," --from=builder \u002Fapp\u002Fnode_modules .\u002Fnode_modules\n",[69,186,188,190],{"class":71,"line":187},14,[69,189,108],{"class":82},[69,191,192],{"class":86}," --from=builder \u002Fapp\u002Fdist .\u002Fdist\n",[69,194,196,198],{"class":71,"line":195},15,[69,197,108],{"class":82},[69,199,111],{"class":86},[69,201,203,206],{"class":71,"line":202},16,[69,204,205],{"class":82},"EXPOSE",[69,207,208],{"class":86}," 3000\n",[69,210,212,215,218,222,225,228],{"class":71,"line":211},17,[69,213,214],{"class":82},"CMD",[69,216,217],{"class":86}," [",[69,219,221],{"class":220},"s4wv1","\"node\"",[69,223,224],{"class":86},", ",[69,226,227],{"class":220},"\"dist\u002Fmain.js\"",[69,229,230],{"class":86},"]\n",[28,232,233,234,49],{},"Résultat : une image qui passe de ~1,2 Go à ",[32,235,236],{},"~180 Mo",[51,238,240],{"id":239},"les-bonnes-pratiques","Les bonnes pratiques",[242,243,244,259,275,281],"ul",{},[245,246,247,250,251,254,255,258],"li",{},[32,248,249],{},"Toujours fixer les versions"," (",[66,252,253],{},"node:22-alpine",", pas ",[66,256,257],{},"latest",").",[245,260,261,267,268,224,271,274],{},[32,262,263,264],{},"Utiliser un ",[66,265,266],{},".dockerignore"," pour exclure ",[66,269,270],{},"node_modules",[66,272,273],{},".git",", les tests.",[245,276,277,280],{},[32,278,279],{},"Passer les secrets via variables d'environnement",", jamais dans l'image.",[245,282,283,286],{},[32,284,285],{},"Combiner avec une CI\u002FCD"," (GitHub Actions) pour builder et pousser l'image automatiquement.",[51,288,290],{"id":289},"aller-plus-loin","Aller plus loin",[28,292,293,294,250,297,302,303,306],{},"Pour la production, j'ajoute généralement un ",[32,295,296],{},"reverse proxy Caddy",[37,298,301],{"href":299,"rel":300},"https:\u002F\u002Fcaddyserver.com\u002Fdocs\u002Fautomatic-https",[41],"HTTPS automatique via Let's Encrypt",") devant le conteneur, et un ",[66,304,305],{},"docker-compose.yml"," pour orchestrer l'API + la base de données PostgreSQL.",[51,308,310],{"id":309},"sources-officielles","Sources officielles",[242,312,313,319,326,332],{},[245,314,315],{},[37,316,318],{"href":39,"rel":317},[41],"Docker — multi-stage builds",[245,320,321],{},[37,322,325],{"href":323,"rel":324},"https:\u002F\u002Fdocs.docker.com\u002Fdevelop\u002Fdevelop-images\u002Fdockerfile_best-practices\u002F",[41],"Docker — meilleures pratiques de build",[245,327,328],{},[37,329,331],{"href":46,"rel":330},[41],"NestJS — documentation officielle",[245,333,334],{},[37,335,338],{"href":336,"rel":337},"https:\u002F\u002Fgithub.com\u002Fnodejs\u002Fdocker-node\u002Fblob\u002Fmain\u002Fdocs\u002FBestPractices.md",[41],"Node.js — Docker officiel",[28,340,341,342,49],{},"Envie d'industrialiser vos déploiements ? ",[37,343,345],{"href":344},"\u002F#contact","Parlons-en",[347,348,349],"style",{},"html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sOPea, html code.shiki .sOPea{--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .suv1-, html code.shiki .suv1-{--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .s4wv1, html code.shiki .s4wv1{--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":64,"searchDepth":96,"depth":96,"links":351},[352,353,354,355],{"id":53,"depth":79,"text":54},{"id":239,"depth":79,"text":240},{"id":289,"depth":79,"text":290},{"id":309,"depth":79,"text":310},"DevOps","2025-05-22","Du Dockerfile à la production sécurisée : la méthode que j'utilise pour containeriser une API NestJS avec builds multi-stage et CI\u002FCD.","md",null,{},"\u002Fblog\u002Fdockeriser-nestjs",{"title":23,"description":358},"blog\u002Fdockeriser-nestjs",[366,34,367,356,368],"Docker","Node.js","CI\u002FCD","2026-06-16","Z39anNnJO95HC1uMr4K_cWdnb2bI-GPKjSW3IwH32S8",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":372},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"m12 19l-7-7l7-7m7 7H5\"\u002F>",1781647567975]