[{"data":1,"prerenderedAt":1312},["ShallowReactive",2],{"\u002Fblog\u002Fautomating-deployment-with-github-actions-and-docker":3,"\u002Fblog\u002Fautomating-deployment-with-github-actions-and-docker-surround":1306},{"id":4,"title":5,"authors":6,"body":13,"category":1296,"date":1297,"description":1298,"extension":1299,"image":1300,"meta":1301,"minRead":96,"navigation":713,"path":1302,"seo":1303,"stem":1304,"__hash__":1305},"blog_fr\u002Fblog\u002F4.automating-deployment-with-github-actions-and-docker.md","Automatiser la création d'images Docker avec GitHub Actions",[7],{"name":8,"avatar":9,"to":11,"twitter":12},"Désiré KOUASSI",{"src":10,"alt":8},"https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F57430025?v=4&s=64","https:\u002F\u002Fx.com\u002Fkdesire09","KouamDesire07",{"type":14,"value":15,"toc":1278},"minimark",[16,20,29,37,42,45,152,155,183,187,228,231,253,257,313,327,331,334,339,367,370,374,399,405,409,471,478,482,558,561,580,584,673,684,694,873,892,896,910,917,957,963,1063,1070,1092,1104,1108,1114,1118,1121,1155,1159,1165,1246,1251,1267,1271,1274],[17,18,5],"h1",{"id":19},"automatiser-la-création-dimages-docker-avec-github-actions",[21,22,23,24,28],"p",{},"Dans le monde du développement moderne, l'automatisation est clé. L'une des tâches les plus courantes est la création et la publication d'images Docker. Au lieu de le faire manuellement à chaque nouvelle version, nous pouvons utiliser ",[25,26,27],"strong",{},"GitHub Actions"," pour l'automatiser.",[21,30,31,32,36],{},"Dans cet article, je vais vous expliquer pas à pas comment fonctionne le workflow de déploiement (",[33,34,35],"code",{},"build-and-push.yml",") que j'utilise pour ce projet.",[38,39,41],"h2",{"id":40},"_1-déclencheurs-triggers-quand-le-workflow-sexécute-t-il","1. Déclencheurs (Triggers) : Quand le workflow s'exécute-t-il ?",[21,43,44],{},"Tout workflow commence par définir les conditions de son exécution.",[46,47,52],"pre",{"className":48,"code":49,"language":50,"meta":51,"style":51},"language-yaml shiki shiki-themes github-light github-dark github-dark","on:\n  push:\n    tags:\n      - 'v*'\n  workflow_dispatch:\n    inputs:\n      tag:\n        description: 'Version tag (ex: v1.0.0)'\n        required: true\n        type: string\n","yaml","",[33,53,54,67,76,84,94,102,110,118,130,141],{"__ignoreMap":51},[55,56,59,63],"span",{"class":57,"line":58},"line",1,[55,60,62],{"class":61},"suiK_","on",[55,64,66],{"class":65},"slsVL",":\n",[55,68,70,74],{"class":57,"line":69},2,[55,71,73],{"class":72},"sByVh","  push",[55,75,66],{"class":65},[55,77,79,82],{"class":57,"line":78},3,[55,80,81],{"class":72},"    tags",[55,83,66],{"class":65},[55,85,87,90],{"class":57,"line":86},4,[55,88,89],{"class":65},"      - ",[55,91,93],{"class":92},"sfrk1","'v*'\n",[55,95,97,100],{"class":57,"line":96},5,[55,98,99],{"class":72},"  workflow_dispatch",[55,101,66],{"class":65},[55,103,105,108],{"class":57,"line":104},6,[55,106,107],{"class":72},"    inputs",[55,109,66],{"class":65},[55,111,113,116],{"class":57,"line":112},7,[55,114,115],{"class":72},"      tag",[55,117,66],{"class":65},[55,119,121,124,127],{"class":57,"line":120},8,[55,122,123],{"class":72},"        description",[55,125,126],{"class":65},": ",[55,128,129],{"class":92},"'Version tag (ex: v1.0.0)'\n",[55,131,133,136,138],{"class":57,"line":132},9,[55,134,135],{"class":72},"        required",[55,137,126],{"class":65},[55,139,140],{"class":61},"true\n",[55,142,144,147,149],{"class":57,"line":143},10,[55,145,146],{"class":72},"        type",[55,148,126],{"class":65},[55,150,151],{"class":92},"string\n",[21,153,154],{},"Ici, le workflow se déclenche de deux manières :",[156,157,158,173],"ul",{},[159,160,161,164,165,168,169,172],"li",{},[25,162,163],{},"Automatiquement"," : À chaque fois qu'un tag Git commençant par ",[33,166,167],{},"v"," (par exemple ",[33,170,171],{},"v1.0.0",") est poussé sur le dépôt.",[159,174,175,178,179,182],{},[25,176,177],{},"Manuellement"," : Grâce à ",[33,180,181],{},"workflow_dispatch",", on peut lancer le workflow depuis l'interface GitHub en spécifiant un tag manuellement.",[38,184,186],{"id":185},"_2-variables-denvironnement","2. Variables d'environnement",[46,188,190],{"className":48,"code":189,"language":50,"meta":51,"style":51},"env:\n  REGISTRY: ghcr.io\n  IMAGE_NAME: ${{ github.repository }}\n  FORCE_JAVASCRIPT_ACTIONS_TO_NODE22: true\n",[33,191,192,199,209,219],{"__ignoreMap":51},[55,193,194,197],{"class":57,"line":58},[55,195,196],{"class":72},"env",[55,198,66],{"class":65},[55,200,201,204,206],{"class":57,"line":69},[55,202,203],{"class":72},"  REGISTRY",[55,205,126],{"class":65},[55,207,208],{"class":92},"ghcr.io\n",[55,210,211,214,216],{"class":57,"line":78},[55,212,213],{"class":72},"  IMAGE_NAME",[55,215,126],{"class":65},[55,217,218],{"class":92},"${{ github.repository }}\n",[55,220,221,224,226],{"class":57,"line":86},[55,222,223],{"class":72},"  FORCE_JAVASCRIPT_ACTIONS_TO_NODE22",[55,225,126],{"class":65},[55,227,140],{"class":61},[21,229,230],{},"Nous définissons quelques variables pour éviter de répéter les mêmes informations :",[156,232,233,247],{},[159,234,235,238,239,242,243,246],{},[33,236,237],{},"REGISTRY"," : Nous utilisons le ",[25,240,241],{},"GitHub Container Registry"," (",[33,244,245],{},"ghcr.io",").",[159,248,249,252],{},[33,250,251],{},"IMAGE_NAME"," : Le nom de l'image correspondra automatiquement au nom de notre dépôt GitHub.",[38,254,256],{"id":255},"_3-configuration-du-job-et-permissions","3. Configuration du Job et Permissions",[46,258,260],{"className":48,"code":259,"language":50,"meta":51,"style":51},"jobs:\n  build-and-push:\n    runs-on: ubuntu-latest\n    permissions:\n      contents: read\n      packages: write\n",[33,261,262,269,276,286,293,303],{"__ignoreMap":51},[55,263,264,267],{"class":57,"line":58},[55,265,266],{"class":72},"jobs",[55,268,66],{"class":65},[55,270,271,274],{"class":57,"line":69},[55,272,273],{"class":72},"  build-and-push",[55,275,66],{"class":65},[55,277,278,281,283],{"class":57,"line":78},[55,279,280],{"class":72},"    runs-on",[55,282,126],{"class":65},[55,284,285],{"class":92},"ubuntu-latest\n",[55,287,288,291],{"class":57,"line":86},[55,289,290],{"class":72},"    permissions",[55,292,66],{"class":65},[55,294,295,298,300],{"class":57,"line":96},[55,296,297],{"class":72},"      contents",[55,299,126],{"class":65},[55,301,302],{"class":92},"read\n",[55,304,305,308,310],{"class":57,"line":104},[55,306,307],{"class":72},"      packages",[55,309,126],{"class":65},[55,311,312],{"class":92},"write\n",[21,314,315,316,319,320,323,324,246],{},"Le job s'exécute sur un environnement Ubuntu fourni par GitHub.\nIl est crucial de configurer les ",[25,317,318],{},"permissions"," correctement. Le workflow a besoin d'un accès en lecture au code source (",[33,321,322],{},"contents: read",") et d'un accès en écriture pour publier l'image Docker (",[33,325,326],{},"packages: write",[38,328,330],{"id":329},"_4-les-étapes-du-workflow-steps","4. Les étapes du Workflow (Steps)",[21,332,333],{},"Voici le cœur du processus, divisé en plusieurs actions.",[335,336,338],"h3",{"id":337},"étape-1-récupération-du-code","Étape 1 : Récupération du code",[46,340,342],{"className":48,"code":341,"language":50,"meta":51,"style":51},"- name: Checkout repository\n  uses: actions\u002Fcheckout@v6\n",[33,343,344,357],{"__ignoreMap":51},[55,345,346,349,352,354],{"class":57,"line":58},[55,347,348],{"class":65},"- ",[55,350,351],{"class":72},"name",[55,353,126],{"class":65},[55,355,356],{"class":92},"Checkout repository\n",[55,358,359,362,364],{"class":57,"line":69},[55,360,361],{"class":72},"  uses",[55,363,126],{"class":65},[55,365,366],{"class":92},"actions\u002Fcheckout@v6\n",[21,368,369],{},"On commence par télécharger le code source du dépôt pour que GitHub Actions puisse travailler dessus.",[335,371,373],{"id":372},"étape-2-préparation-de-docker-buildx","Étape 2 : Préparation de Docker Buildx",[46,375,377],{"className":48,"code":376,"language":50,"meta":51,"style":51},"- name: Set up Docker Buildx\n  uses: docker\u002Fsetup-buildx-action@v4\n",[33,378,379,390],{"__ignoreMap":51},[55,380,381,383,385,387],{"class":57,"line":58},[55,382,348],{"class":65},[55,384,351],{"class":72},[55,386,126],{"class":65},[55,388,389],{"class":92},"Set up Docker Buildx\n",[55,391,392,394,396],{"class":57,"line":69},[55,393,361],{"class":72},[55,395,126],{"class":65},[55,397,398],{"class":92},"docker\u002Fsetup-buildx-action@v4\n",[21,400,401,404],{},[25,402,403],{},"Buildx"," est un plugin Docker indispensable qui offre des fonctionnalités avancées, notamment la mise en cache, ce qui accélère considérablement les builds ultérieurs.",[335,406,408],{"id":407},"étape-3-authentification","Étape 3 : Authentification",[46,410,412],{"className":48,"code":411,"language":50,"meta":51,"style":51},"- name: Log in to GitHub Container Registry\n  uses: docker\u002Flogin-action@v4\n  with:\n    registry: ${{ env.REGISTRY }}\n    username: ${{ github.actor }}\n    password: ${{ secrets.GITHUB_TOKEN }}\n",[33,413,414,425,434,441,451,461],{"__ignoreMap":51},[55,415,416,418,420,422],{"class":57,"line":58},[55,417,348],{"class":65},[55,419,351],{"class":72},[55,421,126],{"class":65},[55,423,424],{"class":92},"Log in to GitHub Container Registry\n",[55,426,427,429,431],{"class":57,"line":69},[55,428,361],{"class":72},[55,430,126],{"class":65},[55,432,433],{"class":92},"docker\u002Flogin-action@v4\n",[55,435,436,439],{"class":57,"line":78},[55,437,438],{"class":72},"  with",[55,440,66],{"class":65},[55,442,443,446,448],{"class":57,"line":86},[55,444,445],{"class":72},"    registry",[55,447,126],{"class":65},[55,449,450],{"class":92},"${{ env.REGISTRY }}\n",[55,452,453,456,458],{"class":57,"line":96},[55,454,455],{"class":72},"    username",[55,457,126],{"class":65},[55,459,460],{"class":92},"${{ github.actor }}\n",[55,462,463,466,468],{"class":57,"line":104},[55,464,465],{"class":72},"    password",[55,467,126],{"class":65},[55,469,470],{"class":92},"${{ secrets.GITHUB_TOKEN }}\n",[21,472,473,474,477],{},"Avant de publier, le workflow doit se connecter au registre. L'avantage d'utiliser GitHub Actions est que le ",[33,475,476],{},"GITHUB_TOKEN"," est généré automatiquement ; pas besoin de créer un secret manuellement.",[335,479,481],{"id":480},"étape-4-gestion-des-tags-et-métadonnées","Étape 4 : Gestion des tags et métadonnées",[46,483,485],{"className":48,"code":484,"language":50,"meta":51,"style":51},"- name: Extract metadata for Docker\n  id: meta\n  uses: docker\u002Fmetadata-action@v6\n  with:\n    images: ${{ env.REGISTRY }}\u002F${{ env.IMAGE_NAME }}\n    tags: |\n      type=ref,event=tag\n      type=raw,value=${{ inputs.tag }},enable=${{ github.event_name == 'workflow_dispatch' && inputs.tag != '' }}\n      type=raw,value=latest,enable=true\n",[33,486,487,498,508,517,523,533,543,548,553],{"__ignoreMap":51},[55,488,489,491,493,495],{"class":57,"line":58},[55,490,348],{"class":65},[55,492,351],{"class":72},[55,494,126],{"class":65},[55,496,497],{"class":92},"Extract metadata for Docker\n",[55,499,500,503,505],{"class":57,"line":69},[55,501,502],{"class":72},"  id",[55,504,126],{"class":65},[55,506,507],{"class":92},"meta\n",[55,509,510,512,514],{"class":57,"line":78},[55,511,361],{"class":72},[55,513,126],{"class":65},[55,515,516],{"class":92},"docker\u002Fmetadata-action@v6\n",[55,518,519,521],{"class":57,"line":86},[55,520,438],{"class":72},[55,522,66],{"class":65},[55,524,525,528,530],{"class":57,"line":96},[55,526,527],{"class":72},"    images",[55,529,126],{"class":65},[55,531,532],{"class":92},"${{ env.REGISTRY }}\u002F${{ env.IMAGE_NAME }}\n",[55,534,535,537,539],{"class":57,"line":104},[55,536,81],{"class":72},[55,538,126],{"class":65},[55,540,542],{"class":541},"so5gQ","|\n",[55,544,545],{"class":57,"line":112},[55,546,547],{"class":92},"      type=ref,event=tag\n",[55,549,550],{"class":57,"line":120},[55,551,552],{"class":92},"      type=raw,value=${{ inputs.tag }},enable=${{ github.event_name == 'workflow_dispatch' && inputs.tag != '' }}\n",[55,554,555],{"class":57,"line":132},[55,556,557],{"class":92},"      type=raw,value=latest,enable=true\n",[21,559,560],{},"Cette action génère intelligemment les tags pour notre image :",[156,562,563,568,573],{},[159,564,565,566,246],{},"Le tag Git déclencheur (",[33,567,171],{},[159,569,570,571,246],{},"Le tag fourni manuellement (en cas d'exécution via ",[33,572,181],{},[159,574,575,576,579],{},"Un tag ",[33,577,578],{},"latest"," appliqué automatiquement pour pointer vers la version la plus récente.",[335,581,583],{"id":582},"étape-5-build-et-push","Étape 5 : Build et Push",[46,585,587],{"className":48,"code":586,"language":50,"meta":51,"style":51},"- name: Build and push Docker image\n  uses: docker\u002Fbuild-push-action@v7\n  with:\n    context: .\n    push: true\n    tags: ${{ steps.meta.outputs.tags }}\n    labels: ${{ steps.meta.outputs.labels }}\n    cache-from: type=gha\n    cache-to: type=gha,mode=max\n",[33,588,589,600,609,615,625,634,643,653,663],{"__ignoreMap":51},[55,590,591,593,595,597],{"class":57,"line":58},[55,592,348],{"class":65},[55,594,351],{"class":72},[55,596,126],{"class":65},[55,598,599],{"class":92},"Build and push Docker image\n",[55,601,602,604,606],{"class":57,"line":69},[55,603,361],{"class":72},[55,605,126],{"class":65},[55,607,608],{"class":92},"docker\u002Fbuild-push-action@v7\n",[55,610,611,613],{"class":57,"line":78},[55,612,438],{"class":72},[55,614,66],{"class":65},[55,616,617,620,622],{"class":57,"line":86},[55,618,619],{"class":72},"    context",[55,621,126],{"class":65},[55,623,624],{"class":61},".\n",[55,626,627,630,632],{"class":57,"line":96},[55,628,629],{"class":72},"    push",[55,631,126],{"class":65},[55,633,140],{"class":61},[55,635,636,638,640],{"class":57,"line":104},[55,637,81],{"class":72},[55,639,126],{"class":65},[55,641,642],{"class":92},"${{ steps.meta.outputs.tags }}\n",[55,644,645,648,650],{"class":57,"line":112},[55,646,647],{"class":72},"    labels",[55,649,126],{"class":65},[55,651,652],{"class":92},"${{ steps.meta.outputs.labels }}\n",[55,654,655,658,660],{"class":57,"line":120},[55,656,657],{"class":72},"    cache-from",[55,659,126],{"class":65},[55,661,662],{"class":92},"type=gha\n",[55,664,665,668,670],{"class":57,"line":132},[55,666,667],{"class":72},"    cache-to",[55,669,126],{"class":65},[55,671,672],{"class":92},"type=gha,mode=max\n",[21,674,675,676,679,680,683],{},"C'est ici que la magie opère. Cette action construit l'image en utilisant le ",[33,677,678],{},"Dockerfile"," situé à la racine (",[33,681,682],{},"context: .","), lui applique les tags générés précédemment, puis la pousse sur le registre.",[21,685,686,687,689,690,693],{},"Voici un exemple de ",[33,688,678],{}," multi-stage adapté à une application Nuxt utilisant ",[33,691,692],{},"pnpm"," :",[46,695,699],{"className":696,"code":697,"language":698,"meta":51,"style":51},"language-dockerfile shiki shiki-themes github-light github-dark github-dark","ARG NODE_VERSION=24.18.0-alpine\n\nFROM node:${NODE_VERSION} AS build\n\nWORKDIR \u002Fapp\nCOPY pnpm-lock.yaml package.json pnpm-workspace.yaml .\u002F\n# COPY patches .\u002Fpatches\n\n# Install pnpm directly and install dependencies\nRUN npm install -g pnpm@10.34.5 && \\\n    pnpm install --frozen-lockfile\n\nCOPY . .\nENV NODE_OPTIONS=\"--max-old-space-size=4096\"\nRUN pnpm build\n\nFROM node:${NODE_VERSION} AS final\nWORKDIR \u002Fapp\nCOPY --from=build \u002Fapp\u002F.output .output\nEXPOSE 3000\nCMD [\"node\", \".output\u002Fserver\u002Findex.mjs\"]\n","dockerfile",[33,700,701,709,715,729,733,741,749,755,759,764,772,778,783,791,803,811,816,828,835,843,852],{"__ignoreMap":51},[55,702,703,706],{"class":57,"line":58},[55,704,705],{"class":541},"ARG",[55,707,708],{"class":65}," NODE_VERSION=24.18.0-alpine\n",[55,710,711],{"class":57,"line":69},[55,712,714],{"emptyLinePlaceholder":713},true,"\n",[55,716,717,720,723,726],{"class":57,"line":78},[55,718,719],{"class":541},"FROM",[55,721,722],{"class":65}," node:${NODE_VERSION} ",[55,724,725],{"class":541},"AS",[55,727,728],{"class":65}," build\n",[55,730,731],{"class":57,"line":86},[55,732,714],{"emptyLinePlaceholder":713},[55,734,735,738],{"class":57,"line":96},[55,736,737],{"class":541},"WORKDIR",[55,739,740],{"class":65}," \u002Fapp\n",[55,742,743,746],{"class":57,"line":104},[55,744,745],{"class":541},"COPY",[55,747,748],{"class":65}," pnpm-lock.yaml package.json pnpm-workspace.yaml .\u002F\n",[55,750,751],{"class":57,"line":112},[55,752,754],{"class":753},"sCsY4","# COPY patches .\u002Fpatches\n",[55,756,757],{"class":57,"line":120},[55,758,714],{"emptyLinePlaceholder":713},[55,760,761],{"class":57,"line":132},[55,762,763],{"class":753},"# Install pnpm directly and install dependencies\n",[55,765,766,769],{"class":57,"line":143},[55,767,768],{"class":541},"RUN",[55,770,771],{"class":65}," npm install -g pnpm@10.34.5 && \\\n",[55,773,775],{"class":57,"line":774},11,[55,776,777],{"class":65},"    pnpm install --frozen-lockfile\n",[55,779,781],{"class":57,"line":780},12,[55,782,714],{"emptyLinePlaceholder":713},[55,784,786,788],{"class":57,"line":785},13,[55,787,745],{"class":541},[55,789,790],{"class":65}," . .\n",[55,792,794,797,800],{"class":57,"line":793},14,[55,795,796],{"class":541},"ENV",[55,798,799],{"class":65}," NODE_OPTIONS=",[55,801,802],{"class":92},"\"--max-old-space-size=4096\"\n",[55,804,806,808],{"class":57,"line":805},15,[55,807,768],{"class":541},[55,809,810],{"class":65}," pnpm build\n",[55,812,814],{"class":57,"line":813},16,[55,815,714],{"emptyLinePlaceholder":713},[55,817,819,821,823,825],{"class":57,"line":818},17,[55,820,719],{"class":541},[55,822,722],{"class":65},[55,824,725],{"class":541},[55,826,827],{"class":65}," final\n",[55,829,831,833],{"class":57,"line":830},18,[55,832,737],{"class":541},[55,834,740],{"class":65},[55,836,838,840],{"class":57,"line":837},19,[55,839,745],{"class":541},[55,841,842],{"class":65}," --from=build \u002Fapp\u002F.output .output\n",[55,844,846,849],{"class":57,"line":845},20,[55,847,848],{"class":541},"EXPOSE",[55,850,851],{"class":65}," 3000\n",[55,853,855,858,861,864,867,870],{"class":57,"line":854},21,[55,856,857],{"class":541},"CMD",[55,859,860],{"class":65}," [",[55,862,863],{"class":92},"\"node\"",[55,865,866],{"class":65},", ",[55,868,869],{"class":92},"\".output\u002Fserver\u002Findex.mjs\"",[55,871,872],{"class":65},"]\n",[21,874,875,879,880,883,884,887,888,891],{},[876,877,878],"em",{},"Note de performance"," : Les paramètres ",[33,881,882],{},"cache-from"," et ",[33,885,886],{},"cache-to"," utilisant ",[33,889,890],{},"type=gha"," (GitHub Actions cache) permettent de sauvegarder les couches Docker entre chaque exécution, réduisant drastiquement le temps de build.",[38,893,895],{"id":894},"_5-lier-ce-workflow-à-release-it","5. Lier ce workflow à Release-It",[21,897,898,899,909],{},"Pour pousser ce niveau d'automatisation encore plus loin, j'utilise l'outil ",[900,901,906],"a",{"href":902,"rel":903,"target":905},"https:\u002F\u002Fgithub.com\u002Frelease-it\u002Frelease-it",[904],"nofollow","_blank",[25,907,908],{},"release-it"," pour générer les tags automatiquement au lieu de le faire avec des commandes Git manuelles.",[21,911,912,913,916],{},"Dans mon fichier ",[33,914,915],{},"package.json",", j'ai un script dédié :",[46,918,922],{"className":919,"code":920,"language":921,"meta":51,"style":51},"language-json shiki shiki-themes github-light github-dark github-dark","{\n  \"scripts\": {\n    \"release\": \"dotenv release-it\"\n  }\n}\n","json",[33,923,924,929,937,947,952],{"__ignoreMap":51},[55,925,926],{"class":57,"line":58},[55,927,928],{"class":65},"{\n",[55,930,931,934],{"class":57,"line":69},[55,932,933],{"class":61},"  \"scripts\"",[55,935,936],{"class":65},": {\n",[55,938,939,942,944],{"class":57,"line":78},[55,940,941],{"class":61},"    \"release\"",[55,943,126],{"class":65},[55,945,946],{"class":92},"\"dotenv release-it\"\n",[55,948,949],{"class":57,"line":86},[55,950,951],{"class":65},"  }\n",[55,953,954],{"class":57,"line":96},[55,955,956],{"class":65},"}\n",[21,958,959,960,693],{},"Et une configuration ",[33,961,962],{},".release-it.json",[46,964,966],{"className":919,"code":965,"language":921,"meta":51,"style":51},"{\n  \"git\": {\n    \"requireCleanWorkingDir\": false,\n    \"tagName\": \"v${version}\",\n    \"commitMessage\": \"chore: release v${version}\"\n  },\n  \"github\": {\n    \"release\": true\n  },\n  \"npm\": {\n    \"publish\": false\n  }\n}\n",[33,967,968,972,979,992,1004,1014,1019,1026,1034,1038,1045,1055,1059],{"__ignoreMap":51},[55,969,970],{"class":57,"line":58},[55,971,928],{"class":65},[55,973,974,977],{"class":57,"line":69},[55,975,976],{"class":61},"  \"git\"",[55,978,936],{"class":65},[55,980,981,984,986,989],{"class":57,"line":78},[55,982,983],{"class":61},"    \"requireCleanWorkingDir\"",[55,985,126],{"class":65},[55,987,988],{"class":61},"false",[55,990,991],{"class":65},",\n",[55,993,994,997,999,1002],{"class":57,"line":86},[55,995,996],{"class":61},"    \"tagName\"",[55,998,126],{"class":65},[55,1000,1001],{"class":92},"\"v${version}\"",[55,1003,991],{"class":65},[55,1005,1006,1009,1011],{"class":57,"line":96},[55,1007,1008],{"class":61},"    \"commitMessage\"",[55,1010,126],{"class":65},[55,1012,1013],{"class":92},"\"chore: release v${version}\"\n",[55,1015,1016],{"class":57,"line":104},[55,1017,1018],{"class":65},"  },\n",[55,1020,1021,1024],{"class":57,"line":112},[55,1022,1023],{"class":61},"  \"github\"",[55,1025,936],{"class":65},[55,1027,1028,1030,1032],{"class":57,"line":120},[55,1029,941],{"class":61},[55,1031,126],{"class":65},[55,1033,140],{"class":61},[55,1035,1036],{"class":57,"line":132},[55,1037,1018],{"class":65},[55,1039,1040,1043],{"class":57,"line":143},[55,1041,1042],{"class":61},"  \"npm\"",[55,1044,936],{"class":65},[55,1046,1047,1050,1052],{"class":57,"line":774},[55,1048,1049],{"class":61},"    \"publish\"",[55,1051,126],{"class":65},[55,1053,1054],{"class":61},"false\n",[55,1056,1057],{"class":57,"line":780},[55,1058,951],{"class":65},[55,1060,1061],{"class":57,"line":785},[55,1062,956],{"class":65},[21,1064,1065,1066,1069],{},"En tapant simplement ",[33,1067,1068],{},"pnpm run release"," dans mon terminal, l'outil me guide pour :",[1071,1072,1073,1076,1082,1089],"ol",{},[159,1074,1075],{},"Choisir le type de version (patch, minor, major).",[159,1077,1078,1079,1081],{},"Mettre à jour la version dans ",[33,1080,915],{},".",[159,1083,1084,1085,1088],{},"Créer le commit et le tag Git (",[33,1086,1087],{},"v1.1.13"," par exemple).",[159,1090,1091],{},"Créer une Release officielle sur GitHub.",[21,1093,1094,1095,1097,1098,866,1100,1103],{},"Dès que ",[33,1096,908],{}," pousse le nouveau tag commençant par ",[33,1099,167],{},[25,1101,1102],{},"notre workflow GitHub Actions se déclenche automatiquement"," !",[38,1105,1107],{"id":1106},"_6-utiliser-limage-docker-générée-dépôts-publics-et-privés","6. Utiliser l'image Docker générée (Dépôts publics et privés)",[21,1109,1110,1111,1081],{},"Une fois le workflow terminé avec succès, votre image Docker est disponible sur le ",[25,1112,1113],{},"GitHub Container Registry (GHCR)",[335,1115,1117],{"id":1116},"si-votre-dépôt-est-public","Si votre dépôt est public",[21,1119,1120],{},"Tout le monde peut télécharger et exécuter votre image sans aucune authentification. Il suffit de lancer :",[46,1122,1126],{"className":1123,"code":1124,"language":1125,"meta":51,"style":51},"language-bash shiki shiki-themes github-light github-dark github-dark","docker pull ghcr.io\u002Fvotre-nom-utilisateur\u002Fvotre-depot:latest\ndocker run -p 3000:3000 ghcr.io\u002Fvotre-nom-utilisateur\u002Fvotre-depot:latest\n","bash",[33,1127,1128,1140],{"__ignoreMap":51},[55,1129,1130,1134,1137],{"class":57,"line":58},[55,1131,1133],{"class":1132},"shcOC","docker",[55,1135,1136],{"class":92}," pull",[55,1138,1139],{"class":92}," ghcr.io\u002Fvotre-nom-utilisateur\u002Fvotre-depot:latest\n",[55,1141,1142,1144,1147,1150,1153],{"class":57,"line":69},[55,1143,1133],{"class":1132},[55,1145,1146],{"class":92}," run",[55,1148,1149],{"class":61}," -p",[55,1151,1152],{"class":92}," 3000:3000",[55,1154,1139],{"class":92},[335,1156,1158],{"id":1157},"si-votre-dépôt-est-privé","Si votre dépôt est privé",[21,1160,1161,1162,1081],{},"Pour les dépôts privés, l'image n'est pas accessible publiquement par défaut. Vous devez d'abord vous authentifier auprès de GHCR avant de pouvoir faire un ",[33,1163,1164],{},"docker pull",[1071,1166,1167,1180,1227],{},[159,1168,1169,1172,1173,1176,1177,1081],{},[25,1170,1171],{},"Créer un Personal Access Token (PAT)"," sur GitHub (dans ",[33,1174,1175],{},"Settings > Developer settings > Personal access tokens","). Ce token doit avoir la permission ",[33,1178,1179],{},"read:packages",[159,1181,1182,1185,1186,1220],{},[25,1183,1184],{},"Se connecter à GHCR depuis votre serveur ou machine locale"," :\n",[46,1187,1189],{"className":1123,"code":1188,"language":1125,"meta":51,"style":51},"echo $CR_PAT | docker login ghcr.io -u votre-nom-utilisateur --password-stdin\n",[33,1190,1191],{"__ignoreMap":51},[55,1192,1193,1196,1199,1202,1205,1208,1211,1214,1217],{"class":57,"line":58},[55,1194,1195],{"class":61},"echo",[55,1197,1198],{"class":65}," $CR_PAT ",[55,1200,1201],{"class":541},"|",[55,1203,1204],{"class":1132}," docker",[55,1206,1207],{"class":92}," login",[55,1209,1210],{"class":92}," ghcr.io",[55,1212,1213],{"class":61}," -u",[55,1215,1216],{"class":92}," votre-nom-utilisateur",[55,1218,1219],{"class":61}," --password-stdin\n",[876,1221,1222,1223,1226],{},"(Ici, ",[33,1224,1225],{},"$CR_PAT"," contient le token que vous avez généré).",[159,1228,1229,1232,1233],{},[25,1230,1231],{},"Télécharger et lancer l'image"," comme d'habitude :\n",[46,1234,1236],{"className":1123,"code":1235,"language":1125,"meta":51,"style":51},"docker pull ghcr.io\u002Fvotre-nom-utilisateur\u002Fvotre-depot:latest\n",[33,1237,1238],{"__ignoreMap":51},[55,1239,1240,1242,1244],{"class":57,"line":58},[55,1241,1133],{"class":1132},[55,1243,1136],{"class":92},[55,1245,1139],{"class":92},[21,1247,1248],{},[876,1249,1250],{},"Astuce : Vous pouvez aussi rendre l'image publique indépendamment de la confidentialité du code source si vous le souhaitez, en modifiant les paramètres de visibilité du package dans l'onglet \"Packages\" de votre compte GitHub.",[21,1252,1253],{},[876,1254,1255,1256,1258,1259,1262,1263,1266],{},"Note sur le tag ",[33,1257,578],{}," : Bien que les exemples ci-dessus utilisent ",[33,1260,1261],{},":latest"," par commodité, vous n'êtes pas obligés de l'utiliser. En environnement de production, il est vivement recommandé de cibler une version spécifique générée par votre workflow (par exemple ",[33,1264,1265],{},":v1.1.13",") pour figer la version et éviter les mauvaises surprises lors des déploiements.",[38,1268,1270],{"id":1269},"conclusion","Conclusion",[21,1272,1273],{},"Avec ce fichier de configuration, publier une nouvelle version de votre application devient aussi simple que de créer un tag Git. L'intégration de la mise en cache et la gestion automatique des tags font de ce workflow une solution robuste et prête pour la production.",[1275,1276,1277],"style",{},"html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .sByVh, html code.shiki .sByVh{--shiki-light:#22863A;--shiki-default:#85E89D;--shiki-dark:#85E89D}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}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);}html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .sCsY4, html code.shiki .sCsY4{--shiki-light:#6A737D;--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}",{"title":51,"searchDepth":69,"depth":69,"links":1279},[1280,1281,1282,1283,1290,1291,1295],{"id":40,"depth":69,"text":41},{"id":185,"depth":69,"text":186},{"id":255,"depth":69,"text":256},{"id":329,"depth":69,"text":330,"children":1284},[1285,1286,1287,1288,1289],{"id":337,"depth":78,"text":338},{"id":372,"depth":78,"text":373},{"id":407,"depth":78,"text":408},{"id":480,"depth":78,"text":481},{"id":582,"depth":78,"text":583},{"id":894,"depth":69,"text":895},{"id":1106,"depth":69,"text":1107,"children":1292},[1293,1294],{"id":1116,"depth":78,"text":1117},{"id":1157,"depth":78,"text":1158},{"id":1269,"depth":69,"text":1270},null,"2026-07-21","Découvrez comment mettre en place un pipeline CI\u002FCD complet avec GitHub Actions pour builder et publier automatiquement vos images Docker sur le GitHub Container Registry.","md","\u002Fimages\u002Fblog\u002Fdocker-github-actions.webp",{},"\u002Fblog\u002Fautomating-deployment-with-github-actions-and-docker",{"title":5,"description":1298},"blog\u002F4.automating-deployment-with-github-actions-and-docker","IQnbTYVG8YvffzApm_wap5k_J4fT49y0kpF2GBHyqYk",[1307,1296],{"title":1308,"path":1309,"stem":1310,"description":1311,"children":-1},"L'IA : Le nouveau compas du développeur, pas son remplaçant","\u002Fblog\u002Fai-the-developers-new-compass","blog\u002F3.ai-the-developers-new-compass","Pourquoi je pense que l'IA ne remplacera pas les développeurs, tout comme la calculatrice n'a pas remplacé les mathématiciens.",1787937217128]