[{"data":1,"prerenderedAt":2192},["ShallowReactive",2],{"author-loic-poullain":3,"author-articles-loic-poullain":22,"authors":1876},{"id":4,"title":5,"body":6,"description":10,"extension":13,"meta":14,"name":15,"navigation":16,"path":17,"readingTime":18,"seo":19,"stem":20,"__hash__":21},"authors\u002Fauthors\u002Floic-poullain.md","Software Engineer",{"type":7,"value":8,"toc":9},"minimark",[],{"title":10,"searchDepth":11,"depth":11,"links":12},"",2,[],"md",{},"Loïc Poullain",true,"\u002Fauthors\u002Floic-poullain",1,{"title":5,"description":10},"authors\u002Floic-poullain","oRIyJhFRTqxy5dLCYQ2OnYZ1DB-gLDUM-85vTSYuTF0",[23,200],{"id":24,"title":25,"author":26,"body":27,"date":189,"description":190,"extension":13,"lang":191,"meta":192,"navigation":16,"path":193,"published":16,"readingTime":194,"seo":195,"stem":196,"tags":197,"__hash__":199},"articles\u002Farticles\u002F2022-10-13-how-to-securely-store-passwords-in-a-database.md","How to securely store passwords in a database?","loic-poullain",{"type":7,"value":28,"toc":185},[29,33,36,41,44,47,53,91,95,98,105,112,117,120,123,126],[30,31,32],"p",{},"Passwords must never be stored in clear text in the database. If they were, attackers would be able\nto steal them if the database ever gets compromised.",[30,34,35],{},"To avoid this, two actions are necessary to store a password securely: hashing and salting.",[37,38,40],"h2",{"id":39},"hashing","Hashing",[30,42,43],{},"A hash function is a one-way function that maps one value to another value of fixed size. Secure\nhash functions are unidirectional: it is not possible to \"decrypt\" the generated hash and get the\noriginal value. They are used to generate password hashes.",[30,45,46],{},"When a user first registers for the application, his or her password is hashed and the result is\nstored in the database. Then, when the user tries to log in again, the submitted password is also\nhashed and the result is compared to the value stored in the database. If the values are equal, the\npassword is correct. If not, the password is incorrect. This way, the password is not stored in the\ndatabase in clear text and if the database is compromised, an attacker will not be able to read the\npasswords.",[30,48,49],{},[50,51],"img",{"alt":10,"src":52},"\u002Fimages\u002FUntitled-19.png",[54,55,56],"blockquote",{},[30,57,58,59,63,64,67,68,75,76,79,80,79,83,86,87,90],{},"Note: Not all hash algorithms are secure for storing passwords. In particular, ",[60,61,62],"em",{},"MD5"," or ",[60,65,66],{},"SHA-1","\nare not suitable because the original password can potentially be guessed by studying the hash.\nAccording to ",[69,70,74],"a",{"href":71,"rel":72},"https:\u002F\u002Fowasp.org\u002F",[73],"nofollow","OWASP",", the currently secure hash functions for storing\npasswords are ",[60,77,78],{},"Argon2id",", ",[60,81,82],{},"bcrypt",[60,84,85],{},"scrypt"," and ",[60,88,89],{},"PBKDF2",".",[37,92,94],{"id":93},"salting","Salting",[30,96,97],{},"Hashing passwords is however not enough. An attacker can defeat one-way hashes with pre-computation\nattacks.",[30,99,100,101,104],{},"If an attacker pre-computes hashes of common passwords and builds what is called a ",[60,102,103],{},"rainbow table",",\nthey will be able to retrieve some of the original passwords by comparing the table's hashes with\nthose stored in the database.",[30,106,107,108,111],{},"To avoid this, a random string, a ",[60,109,110],{},"salt",", can be generated for each password and used during the\nhashing process. In this case, not only does the hash function take the password as input, but it\nalso takes the salt. This implies that two identical passwords will result in a different hash\nbecause they will have a different randomly generated salt used to generate the hash.",[30,113,114],{},[50,115],{"alt":10,"src":116},"\u002Fimages\u002FUntitled-20.png",[30,118,119],{},"More precisely, when a user subscribes to the application for the first time, a salt is generated.\nThis salt and the password are next combined and hashed. The result is stored in the database along\nwith the salt. Then, when the user tries to log in again, the salt is retrieved from the database\nand combined with the submitted password to be hashed. The resulted hash is then compared to the\nvalue stored in the database.",[30,121,122],{},"In this way, if an attacker wants to pre-computes hashes, they will have to pre-compute a hash table\nfor each salt (i.e, each password stored in the database), which considerably increases the required\ncapacity and computing time, making password theft more difficult.",[30,124,125],{},"When properly implemented and with the right algorithms, these two techniques, salting and hashing,\nthus allow passwords to be securely stored in the database.",[54,127,128,134,137,140,150,157,173,176,179,182],{},[30,129,130],{},[131,132,133],"strong",{},"Bonus: algorithm rotation",[30,135,136],{},"Usually, the salt and the hash are not the only two values that are stored in the database. The\nalgorithm and some additional information are also present with them.",[30,138,139],{},"For example, in the case of the Django framework, this is how a password stored in the database\nmight look like:",[141,142,147],"pre",{"className":143,"code":145,"language":146},[144],"language-text","pbkdf2_sha256$150000$B6U8ZKsV963hFZLlsGiOuQ==$ZnaWnEOVWbKQTMdRi4AJ3KrDXeDps7BqKmUIOfXJVVw=\n","text",[148,149,145],"code",{"__ignoreMap":10},[30,151,152,153,156],{},"It consists of four parts, each delimited by the ",[148,154,155],{},"$"," character:",[158,159,160,164,167,170],"ul",{},[161,162,163],"li",{},"the name of the algorithm,",[161,165,166],{},"the number of iterations used by the PBKDF2 algorithm,",[161,168,169],{},"the salt",[161,171,172],{},"and the hash.",[30,174,175],{},"Storing this information is useful in case the number of iterations becomes insufficient (due to\nincreased computational capacity) or if the algorithm is deprecated in favor of more secure ones.\nIn this case, an algorithm rotation can be performed.",[30,177,178],{},"When a user logs in, the application retrieves the algorithm and its arguments (the number of\niterations in this case) from the database. If the algorithm and arguments are considered safe,\nthey are used to hash the submitted password and test if it is valid as usual.",[30,180,181],{},"If the algorithm and arguments are not up to date, the framework performs an additional step.\nAfter the password is verified and approved, a new hash is generated with the latest security\nguidelines and replaces the one previously stored in the database. The algorithm information is\nalso updated.",[30,183,184],{},"This way, it is ensured that as many passwords as possible in the database are hashed with the\nlatest security recommandations.",{"title":10,"searchDepth":11,"depth":11,"links":186},[187,188],{"id":39,"depth":11,"text":40},{"id":93,"depth":11,"text":94},"2022-10-13","Passwords must never be stored in clear text in the database. If they were, attackers would be able to steal them if the database ever gets compromised","en",{},"\u002Farticles\u002F2022-10-13-how-to-securely-store-passwords-in-a-database",5,{"title":25,"description":190},"articles\u002F2022-10-13-how-to-securely-store-passwords-in-a-database",[198],"Tech","pMgZX23ys-j7c7p4ffrVLbVlEzZimpdNLL2CXkO6nn8",{"id":201,"title":202,"author":26,"body":203,"date":1867,"description":1868,"extension":13,"lang":191,"meta":1869,"navigation":16,"path":1870,"published":16,"readingTime":310,"seo":1871,"stem":1872,"tags":1873,"__hash__":1875},"articles\u002Farticles\u002F2022-06-10-how-to-use-vscode-debugger-with-multiple-docker-services.md","How to use VSCode debugger with multiple Docker services",{"type":7,"value":204,"toc":1851},[205,208,211,223,227,234,239,244,331,336,514,519,609,614,620,624,634,638,686,689,714,729,733,737,744,764,768,840,843,861,866,926,929,959,962,966,973,978,1084,1094,1105,1110,1113,1118,1127,1132,1145,1148,1152,1156,1165,1173,1183,1199,1203,1422,1427,1430,1439,1443,1509,1515,1519,1615,1618,1644,1648,1654,1658,1821,1824,1829,1834,1844,1847],[30,206,207],{},"In my company, we use Docker and Docker Compose to run our Node.js services locally. Recently, I\nneeded to configure and run the VSCode debugger on some of these services to debug a feature. There\nare a few things to know to achieve this, which I will share in this article with some basic\nexamples.",[30,209,210],{},"Before we start, here are the points that will serve as a guideline in this tutorial:",[158,212,213,216],{},[161,214,215],{},"We want to keep using Docker and Docker compose to run our services, so that we have the proper\nenvironment for each of these services (environment variables, etc).",[161,217,218,219,222],{},"We do not want to touch the current ",[148,220,221],{},"docker-compose.yml"," which could, potentially, be used in the\nfuture to deploy our services in production.",[37,224,226],{"id":225},"the-sample-application","The Sample Application",[30,228,229,230,233],{},"Let's start by creating a first service. It is a simple web server that concatenates two strings, a\nfirst name and a last name, and returns the result. This service will live in a ",[148,231,232],{},"webapp\u002F"," directory\nat the root of the project.",[235,236,238],"h3",{"id":237},"the-nodejs-code","The Node.JS code",[30,240,241],{},[148,242,243],{},"webapp\u002Fpackage.json",[141,245,249],{"className":246,"code":247,"language":248,"meta":10,"style":10},"language-json shiki shiki-themes github-light github-dark","{\n  \"name\": \"webapp\",\n  \"scripts\": {\n    \"start\": \"node src\u002Fserver.js\"\n  },\n  \"dependencies\": {\n    \"express\": \"^4.16.1\"\n  }\n}\n","json",[148,250,251,259,275,284,295,300,308,319,325],{"__ignoreMap":10},[252,253,255],"span",{"class":254,"line":18},"line",[252,256,258],{"class":257},"sVt8B","{\n",[252,260,261,265,268,272],{"class":254,"line":11},[252,262,264],{"class":263},"sj4cs","  \"name\"",[252,266,267],{"class":257},": ",[252,269,271],{"class":270},"sZZnC","\"webapp\"",[252,273,274],{"class":257},",\n",[252,276,278,281],{"class":254,"line":277},3,[252,279,280],{"class":263},"  \"scripts\"",[252,282,283],{"class":257},": {\n",[252,285,287,290,292],{"class":254,"line":286},4,[252,288,289],{"class":263},"    \"start\"",[252,291,267],{"class":257},[252,293,294],{"class":270},"\"node src\u002Fserver.js\"\n",[252,296,297],{"class":254,"line":194},[252,298,299],{"class":257},"  },\n",[252,301,303,306],{"class":254,"line":302},6,[252,304,305],{"class":263},"  \"dependencies\"",[252,307,283],{"class":257},[252,309,311,314,316],{"class":254,"line":310},7,[252,312,313],{"class":263},"    \"express\"",[252,315,267],{"class":257},[252,317,318],{"class":270},"\"^4.16.1\"\n",[252,320,322],{"class":254,"line":321},8,[252,323,324],{"class":257},"  }\n",[252,326,328],{"class":254,"line":327},9,[252,329,330],{"class":257},"}\n",[30,332,333],{},[148,334,335],{},"webapp\u002Fsrc\u002Fserver.js",[141,337,341],{"className":338,"code":339,"language":340,"meta":10,"style":10},"language-ts shiki shiki-themes github-light github-dark","const express = require(\"express\");\nconst app = express();\n\napp.get(\"\u002Ffullname\", (req, res) => {\n  const firstName = req.query.firstNme;\n  const lastName = req.query.lastName;\n  res.send(`${firstName} ${lastName}`);\n});\n\napp.listen(8080, () => console.log(\"Listening on port 8080...\"));\n","ts",[148,342,343,368,382,387,421,434,446,473,478,482],{"__ignoreMap":10},[252,344,345,349,352,355,359,362,365],{"class":254,"line":18},[252,346,348],{"class":347},"szBVR","const",[252,350,351],{"class":263}," express",[252,353,354],{"class":347}," =",[252,356,358],{"class":357},"sScJk"," require",[252,360,361],{"class":257},"(",[252,363,364],{"class":270},"\"express\"",[252,366,367],{"class":257},");\n",[252,369,370,372,375,377,379],{"class":254,"line":11},[252,371,348],{"class":347},[252,373,374],{"class":263}," app",[252,376,354],{"class":347},[252,378,351],{"class":357},[252,380,381],{"class":257},"();\n",[252,383,384],{"class":254,"line":277},[252,385,386],{"emptyLinePlaceholder":16},"\n",[252,388,389,392,395,397,400,403,407,409,412,415,418],{"class":254,"line":286},[252,390,391],{"class":257},"app.",[252,393,394],{"class":357},"get",[252,396,361],{"class":257},[252,398,399],{"class":270},"\"\u002Ffullname\"",[252,401,402],{"class":257},", (",[252,404,406],{"class":405},"s4XuR","req",[252,408,79],{"class":257},[252,410,411],{"class":405},"res",[252,413,414],{"class":257},") ",[252,416,417],{"class":347},"=>",[252,419,420],{"class":257}," {\n",[252,422,423,426,429,431],{"class":254,"line":194},[252,424,425],{"class":347},"  const",[252,427,428],{"class":263}," firstName",[252,430,354],{"class":347},[252,432,433],{"class":257}," req.query.firstNme;\n",[252,435,436,438,441,443],{"class":254,"line":302},[252,437,425],{"class":347},[252,439,440],{"class":263}," lastName",[252,442,354],{"class":347},[252,444,445],{"class":257}," req.query.lastName;\n",[252,447,448,451,454,456,459,462,465,468,471],{"class":254,"line":310},[252,449,450],{"class":257},"  res.",[252,452,453],{"class":357},"send",[252,455,361],{"class":257},[252,457,458],{"class":270},"`${",[252,460,461],{"class":257},"firstName",[252,463,464],{"class":270},"} ${",[252,466,467],{"class":257},"lastName",[252,469,470],{"class":270},"}`",[252,472,367],{"class":257},[252,474,475],{"class":254,"line":321},[252,476,477],{"class":257},"});\n",[252,479,480],{"class":254,"line":327},[252,481,386],{"emptyLinePlaceholder":16},[252,483,485,487,490,492,495,498,500,503,506,508,511],{"class":254,"line":484},10,[252,486,391],{"class":257},[252,488,489],{"class":357},"listen",[252,491,361],{"class":257},[252,493,494],{"class":263},"8080",[252,496,497],{"class":257},", () ",[252,499,417],{"class":347},[252,501,502],{"class":257}," console.",[252,504,505],{"class":357},"log",[252,507,361],{"class":257},[252,509,510],{"class":270},"\"Listening on port 8080...\"",[252,512,513],{"class":257},"));\n",[30,515,516],{},[148,517,518],{},"webapp\u002FDockerfile",[141,520,524],{"className":521,"code":522,"language":523,"meta":10,"style":10},"language-dockerfile shiki shiki-themes github-light github-dark","FROM node:16\n\nWORKDIR \u002Fusr\u002Fsrc\u002Fapp\n\nCOPY package*.json .\u002F\n\nRUN npm install\nCOPY . .\n\nEXPOSE 8080\nCMD [ \"node\", \"src\u002Fserver.js\" ]\n","dockerfile",[148,525,526,534,538,546,550,558,562,570,577,581,589],{"__ignoreMap":10},[252,527,528,531],{"class":254,"line":18},[252,529,530],{"class":347},"FROM",[252,532,533],{"class":257}," node:16\n",[252,535,536],{"class":254,"line":11},[252,537,386],{"emptyLinePlaceholder":16},[252,539,540,543],{"class":254,"line":277},[252,541,542],{"class":347},"WORKDIR",[252,544,545],{"class":257}," \u002Fusr\u002Fsrc\u002Fapp\n",[252,547,548],{"class":254,"line":286},[252,549,386],{"emptyLinePlaceholder":16},[252,551,552,555],{"class":254,"line":194},[252,553,554],{"class":347},"COPY",[252,556,557],{"class":257}," package*.json .\u002F\n",[252,559,560],{"class":254,"line":302},[252,561,386],{"emptyLinePlaceholder":16},[252,563,564,567],{"class":254,"line":310},[252,565,566],{"class":347},"RUN",[252,568,569],{"class":257}," npm install\n",[252,571,572,574],{"class":254,"line":321},[252,573,554],{"class":347},[252,575,576],{"class":257}," . .\n",[252,578,579],{"class":254,"line":327},[252,580,386],{"emptyLinePlaceholder":16},[252,582,583,586],{"class":254,"line":484},[252,584,585],{"class":347},"EXPOSE",[252,587,588],{"class":257}," 8080\n",[252,590,592,595,598,601,603,606],{"class":254,"line":591},11,[252,593,594],{"class":347},"CMD",[252,596,597],{"class":257}," [ ",[252,599,600],{"class":270},"\"node\"",[252,602,79],{"class":257},[252,604,605],{"class":270},"\"src\u002Fserver.js\"",[252,607,608],{"class":257}," ]\n",[30,610,611],{},[148,612,613],{},"webapp\u002F.dockerignore",[141,615,618],{"className":616,"code":617,"language":146},[144],"node_modules\nnpm-debug.log\n",[148,619,617],{"__ignoreMap":10},[235,621,623],{"id":622},"the-docker-configuration","The Docker configuration",[30,625,626,627,630,631,633],{},"Now that the application code is written and the ",[148,628,629],{},"Dockerfile"," created, we can add a\n",[148,632,221],{}," file at the root of the project.",[30,635,636],{},[148,637,221],{},[141,639,643],{"className":640,"code":641,"language":642,"meta":10,"style":10},"language-yml shiki shiki-themes github-light github-dark","services:\n  webapp:\n        build: .\u002Fwebapp\n        ports:\n            - \"127.0.0.1:8080:8080\"\n","yml",[148,644,645,654,661,671,678],{"__ignoreMap":10},[252,646,647,651],{"class":254,"line":18},[252,648,650],{"class":649},"s9eBZ","services",[252,652,653],{"class":257},":\n",[252,655,656,659],{"class":254,"line":11},[252,657,658],{"class":649},"  webapp",[252,660,653],{"class":257},[252,662,663,666,668],{"class":254,"line":277},[252,664,665],{"class":649},"        build",[252,667,267],{"class":257},[252,669,670],{"class":270},".\u002Fwebapp\n",[252,672,673,676],{"class":254,"line":286},[252,674,675],{"class":649},"        ports",[252,677,653],{"class":257},[252,679,680,683],{"class":254,"line":194},[252,681,682],{"class":257},"            - ",[252,684,685],{"class":270},"\"127.0.0.1:8080:8080\"\n",[30,687,688],{},"Let's start the service.",[141,690,694],{"className":691,"code":692,"language":693,"meta":10,"style":10},"language-sh shiki shiki-themes github-light github-dark","docker-compose build\ndocker-compose up -d\n","sh",[148,695,696,704],{"__ignoreMap":10},[252,697,698,701],{"class":254,"line":18},[252,699,700],{"class":357},"docker-compose",[252,702,703],{"class":270}," build\n",[252,705,706,708,711],{"class":254,"line":11},[252,707,700],{"class":357},[252,709,710],{"class":270}," up",[252,712,713],{"class":263}," -d\n",[30,715,716,717,721,724,725,728],{},"If you go to\n",[69,718],{"href":719,"rel":720},"http:\u002F\u002Flocalhost:8080\u002Ffullname?firstName=Foo&lastName=Bar",[73],[69,722,719],{"href":719,"rel":723},[73],",\nyou should see the string ",[148,726,727],{},"undefined Bar",", which is the unexpected behavior we will debug.",[37,730,732],{"id":731},"debugging-the-application-in-docker-with-vscode","Debugging the Application in Docker with VSCode",[235,734,736],{"id":735},"the-debugger-command","The debugger command",[30,738,739,740,743],{},"To allow the future VSCode debugger to attach to the Node service, we need to specify it when we\nstart the process by adding the ",[148,741,742],{},"--inpect"," flag.",[54,745,746],{},[30,747,748,749,63,752,755,756,759,760,763],{},"Simply using ",[148,750,751],{},"--inspect",[148,753,754],{},"--inspect=127.0.0.1:9229"," is not sufficient here because we need the\n",[148,757,758],{},"9229"," port to be accessible from outside the service, which is allowed by the ",[148,761,762],{},"0.0.0.0"," address.\nSo this command should only be used when you run the debugger in a Docker service. Otherwise, you\nwould expose the port and the debugger to anyone on the Internet.",[30,765,766],{},[148,767,243],{},[141,769,771],{"className":246,"code":770,"language":248,"meta":10,"style":10},"{\n  \"name\": \"webapp\",\n  \"scripts\": {\n    \"start\": \"node src\u002Fserver.js\",\n    \"start:docker:debug\": \"node --inspect=0.0.0.0:9229 src\u002Fserver.js\"\n  },\n  \"dependencies\": {\n    \"express\": \"^4.16.1\"\n  }\n}\n",[148,772,773,777,787,793,804,814,818,824,832,836],{"__ignoreMap":10},[252,774,775],{"class":254,"line":18},[252,776,258],{"class":257},[252,778,779,781,783,785],{"class":254,"line":11},[252,780,264],{"class":263},[252,782,267],{"class":257},[252,784,271],{"class":270},[252,786,274],{"class":257},[252,788,789,791],{"class":254,"line":277},[252,790,280],{"class":263},[252,792,283],{"class":257},[252,794,795,797,799,802],{"class":254,"line":286},[252,796,289],{"class":263},[252,798,267],{"class":257},[252,800,801],{"class":270},"\"node src\u002Fserver.js\"",[252,803,274],{"class":257},[252,805,806,809,811],{"class":254,"line":194},[252,807,808],{"class":263},"    \"start:docker:debug\"",[252,810,267],{"class":257},[252,812,813],{"class":270},"\"node --inspect=0.0.0.0:9229 src\u002Fserver.js\"\n",[252,815,816],{"class":254,"line":302},[252,817,299],{"class":257},[252,819,820,822],{"class":254,"line":310},[252,821,305],{"class":263},[252,823,283],{"class":257},[252,825,826,828,830],{"class":254,"line":321},[252,827,313],{"class":263},[252,829,267],{"class":257},[252,831,318],{"class":270},[252,833,834],{"class":254,"line":327},[252,835,324],{"class":257},[252,837,838],{"class":254,"line":484},[252,839,330],{"class":257},[235,841,623],{"id":842},"the-docker-configuration-1",[30,844,845,846,848,849,852,853,857,858,860],{},"Following our guideline, we do not modify the initial ",[148,847,221],{}," but create a second one\nthat extends the first one. We will use the ",[148,850,851],{},"[f","\nflag](",[69,854,855],{"href":855,"rel":856},"https:\u002F\u002Fdocs.docker.com\u002Fcompose\u002Freference\u002F#use--f-to-specify-name-and-path-of-one-or-more-compose-files",[73],")\nof the ",[148,859,700],{}," CLI to use them both.",[30,862,863],{},[148,864,865],{},"docker-compose.debug.yml",[141,867,869],{"className":640,"code":868,"language":642,"meta":10,"style":10},"services:\n    webapp:\n        command: [ 'npm', 'run', 'start:docker:debug' ]\n        ports:\n            - \"127.0.0.1:8080:8080\"\n            - \"127.0.0.1:9229:9229\"\n",[148,870,871,877,884,907,913,919],{"__ignoreMap":10},[252,872,873,875],{"class":254,"line":18},[252,874,650],{"class":649},[252,876,653],{"class":257},[252,878,879,882],{"class":254,"line":11},[252,880,881],{"class":649},"    webapp",[252,883,653],{"class":257},[252,885,886,889,892,895,897,900,902,905],{"class":254,"line":277},[252,887,888],{"class":649},"        command",[252,890,891],{"class":257},": [ ",[252,893,894],{"class":270},"'npm'",[252,896,79],{"class":257},[252,898,899],{"class":270},"'run'",[252,901,79],{"class":257},[252,903,904],{"class":270},"'start:docker:debug'",[252,906,608],{"class":257},[252,908,909,911],{"class":254,"line":286},[252,910,675],{"class":649},[252,912,653],{"class":257},[252,914,915,917],{"class":254,"line":194},[252,916,682],{"class":257},[252,918,685],{"class":270},[252,920,921,923],{"class":254,"line":302},[252,922,682],{"class":257},[252,924,925],{"class":270},"\"127.0.0.1:9229:9229\"\n",[30,927,928],{},"Then, to restart the service with debug mode enabled, you can use this command:",[141,930,932],{"className":691,"code":931,"language":693,"meta":10,"style":10},"docker-compose build\ndocker-compose -f docker-compose.yml -f docker-compose.debug.yml up -d\n",[148,933,934,940],{"__ignoreMap":10},[252,935,936,938],{"class":254,"line":18},[252,937,700],{"class":357},[252,939,703],{"class":270},[252,941,942,944,947,950,952,955,957],{"class":254,"line":11},[252,943,700],{"class":357},[252,945,946],{"class":263}," -f",[252,948,949],{"class":270}," docker-compose.yml",[252,951,946],{"class":263},[252,953,954],{"class":270}," docker-compose.debug.yml",[252,956,710],{"class":270},[252,958,713],{"class":263},[30,960,961],{},"The service is now ready to be attached to the VSCode debugger.",[235,963,965],{"id":964},"running-the-debugger-with-vscode","Running the debugger with VSCode",[30,967,968,969,972],{},"At the root of your project, create a new directory ",[148,970,971],{},".vscode"," and add the following configuration\nfile.",[30,974,975],{},[148,976,977],{},".vscode\u002Flaunch.json",[141,979,981],{"className":246,"code":980,"language":248,"meta":10,"style":10},"{\n  \"version\": \"0.2.0\",\n  \"configurations\": [\n    {\n      \"type\": \"node\",\n      \"request\": \"attach\",\n      \"name\": \"Debug webapp\",\n      \"remoteRoot\": \"\u002Fapp\u002Fsrc\",\n      \"localRoot\": \"${workspaceFolder}\u002Fwebapp\u002Fsrc\"\n    }\n  ]\n}\n",[148,982,983,987,999,1007,1012,1023,1035,1047,1059,1069,1074,1079],{"__ignoreMap":10},[252,984,985],{"class":254,"line":18},[252,986,258],{"class":257},[252,988,989,992,994,997],{"class":254,"line":11},[252,990,991],{"class":263},"  \"version\"",[252,993,267],{"class":257},[252,995,996],{"class":270},"\"0.2.0\"",[252,998,274],{"class":257},[252,1000,1001,1004],{"class":254,"line":277},[252,1002,1003],{"class":263},"  \"configurations\"",[252,1005,1006],{"class":257},": [\n",[252,1008,1009],{"class":254,"line":286},[252,1010,1011],{"class":257},"    {\n",[252,1013,1014,1017,1019,1021],{"class":254,"line":194},[252,1015,1016],{"class":263},"      \"type\"",[252,1018,267],{"class":257},[252,1020,600],{"class":270},[252,1022,274],{"class":257},[252,1024,1025,1028,1030,1033],{"class":254,"line":302},[252,1026,1027],{"class":263},"      \"request\"",[252,1029,267],{"class":257},[252,1031,1032],{"class":270},"\"attach\"",[252,1034,274],{"class":257},[252,1036,1037,1040,1042,1045],{"class":254,"line":310},[252,1038,1039],{"class":263},"      \"name\"",[252,1041,267],{"class":257},[252,1043,1044],{"class":270},"\"Debug webapp\"",[252,1046,274],{"class":257},[252,1048,1049,1052,1054,1057],{"class":254,"line":321},[252,1050,1051],{"class":263},"      \"remoteRoot\"",[252,1053,267],{"class":257},[252,1055,1056],{"class":270},"\"\u002Fapp\u002Fsrc\"",[252,1058,274],{"class":257},[252,1060,1061,1064,1066],{"class":254,"line":327},[252,1062,1063],{"class":263},"      \"localRoot\"",[252,1065,267],{"class":257},[252,1067,1068],{"class":270},"\"${workspaceFolder}\u002Fwebapp\u002Fsrc\"\n",[252,1070,1071],{"class":254,"line":484},[252,1072,1073],{"class":257},"    }\n",[252,1075,1076],{"class":254,"line":591},[252,1077,1078],{"class":257},"  ]\n",[252,1080,1082],{"class":254,"line":1081},12,[252,1083,330],{"class":257},[30,1085,1086,1087,86,1090,1093],{},"When adding a breakpoint, the ",[148,1088,1089],{},"remoteRoot",[148,1091,1092],{},"localRoot"," properties will match the file's position\nin the VSCode environment and its location in the Docker service file system.",[30,1095,1096,1097,1100,1101,1104],{},"You can now start the debugger on the ",[148,1098,1099],{},"webapp"," service. Open the debugging panel and select the\n",[148,1102,1103],{},"Debug webapp"," option. Then click on the play button.",[30,1106,1107],{},[50,1108],{"alt":10,"src":1109},"\u002Fimages\u002Fstart-debugger.png",[30,1111,1112],{},"The debugger is started.",[30,1114,1115],{},[50,1116],{"alt":10,"src":1117},"\u002Fimages\u002Fadd-breakpoint.png",[30,1119,1120,1121,1124,90],{},"Add a breakpoint on line 6 and then go to\n",[69,1122],{"href":719,"rel":1123},[73],[69,1125,719],{"href":719,"rel":1126},[73],[30,1128,1129],{},[50,1130],{"alt":10,"src":1131},"\u002Fimages\u002Frun-debugger.png",[30,1133,1134,1135,1137,1138,1141,1142,1144],{},"The debugger stops on line 6 and we can see that the variable ",[148,1136,461],{}," is ",[148,1139,1140],{},"undefined",". The\nproblem comes from line 5 where this is a typo on the ",[148,1143,461],{}," parameter name.",[30,1146,1147],{},"To close the debugger, click on the button with a red square.",[37,1149,1151],{"id":1150},"debugging-multiple-docker-services","Debugging Multiple Docker Services",[235,1153,1155],{"id":1154},"the-nodejs-micro-service","The Node.JS micro-service",[30,1157,1158,1159,1162,1163,90],{},"To take this a step further, we will add another service, named ",[148,1160,1161],{},"micro-service",", which will be\ncalled by ",[148,1164,1099],{},[30,1166,1167,1168,1170,1171,90],{},"First, copy and paste the contents of the ",[148,1169,1099],{}," directory into another directory named\n",[148,1172,1161],{},[30,1174,1175,1176,1178,1179,1182],{},"Then, in the ",[148,1177,1099],{}," directory, install ",[148,1180,1181],{},"axios"," and update the code as follows.",[141,1184,1186],{"className":691,"code":1185,"language":693,"meta":10,"style":10},"npm install axios\n",[148,1187,1188],{"__ignoreMap":10},[252,1189,1190,1193,1196],{"class":254,"line":18},[252,1191,1192],{"class":357},"npm",[252,1194,1195],{"class":270}," install",[252,1197,1198],{"class":270}," axios\n",[30,1200,1201],{},[148,1202,335],{},[141,1204,1206],{"className":338,"code":1205,"language":340,"meta":10,"style":10},"const express = require(\"express\");\nconst axios = require(\"axios\");\n\nconst app = express();\n\napp.get(\"\u002Ffullname\", async (req, res, next) => {\n  try {\n    const { data: fullName } = await axios.get(\"\u003Chttp:\u002F\u002Fmicro-service:8080\u002Ffullname>\", {\n      params: req.query,\n    });\n    res.send(fullName);\n  } catch (err) {\n    next(err);\n  }\n});\n\napp.listen(8080, () => console.log(\"Listening on port 8080...\"));\n",[148,1207,1208,1224,1242,1246,1258,1262,1297,1304,1342,1347,1352,1362,1373,1382,1387,1392,1397],{"__ignoreMap":10},[252,1209,1210,1212,1214,1216,1218,1220,1222],{"class":254,"line":18},[252,1211,348],{"class":347},[252,1213,351],{"class":263},[252,1215,354],{"class":347},[252,1217,358],{"class":357},[252,1219,361],{"class":257},[252,1221,364],{"class":270},[252,1223,367],{"class":257},[252,1225,1226,1228,1231,1233,1235,1237,1240],{"class":254,"line":11},[252,1227,348],{"class":347},[252,1229,1230],{"class":263}," axios",[252,1232,354],{"class":347},[252,1234,358],{"class":357},[252,1236,361],{"class":257},[252,1238,1239],{"class":270},"\"axios\"",[252,1241,367],{"class":257},[252,1243,1244],{"class":254,"line":277},[252,1245,386],{"emptyLinePlaceholder":16},[252,1247,1248,1250,1252,1254,1256],{"class":254,"line":286},[252,1249,348],{"class":347},[252,1251,374],{"class":263},[252,1253,354],{"class":347},[252,1255,351],{"class":357},[252,1257,381],{"class":257},[252,1259,1260],{"class":254,"line":194},[252,1261,386],{"emptyLinePlaceholder":16},[252,1263,1264,1266,1268,1270,1272,1274,1277,1280,1282,1284,1286,1288,1291,1293,1295],{"class":254,"line":302},[252,1265,391],{"class":257},[252,1267,394],{"class":357},[252,1269,361],{"class":257},[252,1271,399],{"class":270},[252,1273,79],{"class":257},[252,1275,1276],{"class":347},"async",[252,1278,1279],{"class":257}," (",[252,1281,406],{"class":405},[252,1283,79],{"class":257},[252,1285,411],{"class":405},[252,1287,79],{"class":257},[252,1289,1290],{"class":405},"next",[252,1292,414],{"class":257},[252,1294,417],{"class":347},[252,1296,420],{"class":257},[252,1298,1299,1302],{"class":254,"line":310},[252,1300,1301],{"class":347},"  try",[252,1303,420],{"class":257},[252,1305,1306,1309,1312,1315,1317,1320,1323,1326,1329,1332,1334,1336,1339],{"class":254,"line":321},[252,1307,1308],{"class":347},"    const",[252,1310,1311],{"class":257}," { ",[252,1313,1314],{"class":405},"data",[252,1316,267],{"class":257},[252,1318,1319],{"class":263},"fullName",[252,1321,1322],{"class":257}," } ",[252,1324,1325],{"class":347},"=",[252,1327,1328],{"class":347}," await",[252,1330,1331],{"class":257}," axios.",[252,1333,394],{"class":357},[252,1335,361],{"class":257},[252,1337,1338],{"class":270},"\"\u003Chttp:\u002F\u002Fmicro-service:8080\u002Ffullname>\"",[252,1340,1341],{"class":257},", {\n",[252,1343,1344],{"class":254,"line":327},[252,1345,1346],{"class":257},"      params: req.query,\n",[252,1348,1349],{"class":254,"line":484},[252,1350,1351],{"class":257},"    });\n",[252,1353,1354,1357,1359],{"class":254,"line":591},[252,1355,1356],{"class":257},"    res.",[252,1358,453],{"class":357},[252,1360,1361],{"class":257},"(fullName);\n",[252,1363,1364,1367,1370],{"class":254,"line":1081},[252,1365,1366],{"class":257},"  } ",[252,1368,1369],{"class":347},"catch",[252,1371,1372],{"class":257}," (err) {\n",[252,1374,1376,1379],{"class":254,"line":1375},13,[252,1377,1378],{"class":357},"    next",[252,1380,1381],{"class":257},"(err);\n",[252,1383,1385],{"class":254,"line":1384},14,[252,1386,324],{"class":257},[252,1388,1390],{"class":254,"line":1389},15,[252,1391,477],{"class":257},[252,1393,1395],{"class":254,"line":1394},16,[252,1396,386],{"emptyLinePlaceholder":16},[252,1398,1400,1402,1404,1406,1408,1410,1412,1414,1416,1418,1420],{"class":254,"line":1399},17,[252,1401,391],{"class":257},[252,1403,489],{"class":357},[252,1405,361],{"class":257},[252,1407,494],{"class":263},[252,1409,497],{"class":257},[252,1411,417],{"class":347},[252,1413,502],{"class":257},[252,1415,505],{"class":357},[252,1417,361],{"class":257},[252,1419,510],{"class":270},[252,1421,513],{"class":257},[54,1423,1424],{},[30,1425,1426],{},"The URL used line 8 is based on the name of the Docker service defined in the next section.",[235,1428,623],{"id":1429},"the-docker-configuration-2",[30,1431,1432,1433,1435,1436,1438],{},"Add the new service to your ",[148,1434,221],{},". Note that it uses a different port so as not to\nconflict with the ",[148,1437,1099],{}," service.",[30,1440,1441],{},[148,1442,221],{},[141,1444,1446],{"className":640,"code":1445,"language":642,"meta":10,"style":10},"services:\n    webapp:\n        build: .\u002Fwebapp\n        ports:\n            - \"127.0.0.1:8080:8080\"\n    micro-service:\n        build: .\u002Fmicro-service\n        ports:\n            - \"127.0.0.1:3001:8080\"\n",[148,1447,1448,1454,1460,1468,1474,1480,1487,1496,1502],{"__ignoreMap":10},[252,1449,1450,1452],{"class":254,"line":18},[252,1451,650],{"class":649},[252,1453,653],{"class":257},[252,1455,1456,1458],{"class":254,"line":11},[252,1457,881],{"class":649},[252,1459,653],{"class":257},[252,1461,1462,1464,1466],{"class":254,"line":277},[252,1463,665],{"class":649},[252,1465,267],{"class":257},[252,1467,670],{"class":270},[252,1469,1470,1472],{"class":254,"line":286},[252,1471,675],{"class":649},[252,1473,653],{"class":257},[252,1475,1476,1478],{"class":254,"line":194},[252,1477,682],{"class":257},[252,1479,685],{"class":270},[252,1481,1482,1485],{"class":254,"line":302},[252,1483,1484],{"class":649},"    micro-service",[252,1486,653],{"class":257},[252,1488,1489,1491,1493],{"class":254,"line":310},[252,1490,665],{"class":649},[252,1492,267],{"class":257},[252,1494,1495],{"class":270},".\u002Fmicro-service\n",[252,1497,1498,1500],{"class":254,"line":321},[252,1499,675],{"class":649},[252,1501,653],{"class":257},[252,1503,1504,1506],{"class":254,"line":327},[252,1505,682],{"class":257},[252,1507,1508],{"class":270},"\"127.0.0.1:3001:8080\"\n",[30,1510,1511,1512,1514],{},"Then, in your ",[148,1513,865],{},", add the new service as well. Note that the debugger port\nis also different from the first one.",[30,1516,1517],{},[148,1518,865],{},[141,1520,1522],{"className":640,"code":1521,"language":642,"meta":10,"style":10},"services:\n    webapp:\n        command: [ 'npm', 'run', 'start:docker:debug' ]\n        ports:\n            - \"127.0.0.1:8080:8080\"\n            - \"127.0.0.1:9229:9229\"\n    micro-service:\n        command: [ 'npm', 'run', 'start:docker:debug' ]\n        ports:\n            - \"127.0.0.1:3001:8080\"\n            - \"127.0.0.1:9230:9229\"\n",[148,1523,1524,1530,1536,1554,1560,1566,1572,1578,1596,1602,1608],{"__ignoreMap":10},[252,1525,1526,1528],{"class":254,"line":18},[252,1527,650],{"class":649},[252,1529,653],{"class":257},[252,1531,1532,1534],{"class":254,"line":11},[252,1533,881],{"class":649},[252,1535,653],{"class":257},[252,1537,1538,1540,1542,1544,1546,1548,1550,1552],{"class":254,"line":277},[252,1539,888],{"class":649},[252,1541,891],{"class":257},[252,1543,894],{"class":270},[252,1545,79],{"class":257},[252,1547,899],{"class":270},[252,1549,79],{"class":257},[252,1551,904],{"class":270},[252,1553,608],{"class":257},[252,1555,1556,1558],{"class":254,"line":286},[252,1557,675],{"class":649},[252,1559,653],{"class":257},[252,1561,1562,1564],{"class":254,"line":194},[252,1563,682],{"class":257},[252,1565,685],{"class":270},[252,1567,1568,1570],{"class":254,"line":302},[252,1569,682],{"class":257},[252,1571,925],{"class":270},[252,1573,1574,1576],{"class":254,"line":310},[252,1575,1484],{"class":649},[252,1577,653],{"class":257},[252,1579,1580,1582,1584,1586,1588,1590,1592,1594],{"class":254,"line":321},[252,1581,888],{"class":649},[252,1583,891],{"class":257},[252,1585,894],{"class":270},[252,1587,79],{"class":257},[252,1589,899],{"class":270},[252,1591,79],{"class":257},[252,1593,904],{"class":270},[252,1595,608],{"class":257},[252,1597,1598,1600],{"class":254,"line":327},[252,1599,675],{"class":649},[252,1601,653],{"class":257},[252,1603,1604,1606],{"class":254,"line":484},[252,1605,682],{"class":257},[252,1607,1508],{"class":270},[252,1609,1610,1612],{"class":254,"line":591},[252,1611,682],{"class":257},[252,1613,1614],{"class":270},"\"127.0.0.1:9230:9229\"\n",[30,1616,1617],{},"Now build and start the two services.",[141,1619,1620],{"className":691,"code":931,"language":693,"meta":10,"style":10},[148,1621,1622,1628],{"__ignoreMap":10},[252,1623,1624,1626],{"class":254,"line":18},[252,1625,700],{"class":357},[252,1627,703],{"class":270},[252,1629,1630,1632,1634,1636,1638,1640,1642],{"class":254,"line":11},[252,1631,700],{"class":357},[252,1633,946],{"class":263},[252,1635,949],{"class":270},[252,1637,946],{"class":263},[252,1639,954],{"class":270},[252,1641,710],{"class":270},[252,1643,713],{"class":263},[235,1645,1647],{"id":1646},"running-multiple-debuggers-with-vscode","Running multiple debuggers with VSCode",[30,1649,1650,1651,90],{},"The last thing to do is to add the configuration of the second debugger in ",[148,1652,1653],{},"launch.json",[30,1655,1656],{},[148,1657,977],{},[141,1659,1661],{"className":246,"code":1660,"language":248,"meta":10,"style":10},"{\n  \"version\": \"0.2.0\",\n  \"configurations\": [\n    {\n      \"type\": \"node\",\n      \"request\": \"attach\",\n      \"name\": \"Debug webapp\",\n      \"remoteRoot\": \"\u002Fapp\u002Fsrc\",\n      \"localRoot\": \"${workspaceFolder}\u002Fwebapp\u002Fsrc\"\n    },\n    {\n      \"type\": \"node\",\n      \"request\": \"attach\",\n      \"name\": \"Debug micro-service\",\n      \"port\": 9230,\n      \"remoteRoot\": \"\u002Fapp\u002Fsrc\",\n      \"localRoot\": \"${workspaceFolder}\u002Fmicro-service\u002Fsrc\"\n    }\n  ]\n}\n",[148,1662,1663,1667,1677,1683,1687,1697,1707,1717,1727,1735,1740,1744,1754,1764,1775,1787,1797,1806,1811,1816],{"__ignoreMap":10},[252,1664,1665],{"class":254,"line":18},[252,1666,258],{"class":257},[252,1668,1669,1671,1673,1675],{"class":254,"line":11},[252,1670,991],{"class":263},[252,1672,267],{"class":257},[252,1674,996],{"class":270},[252,1676,274],{"class":257},[252,1678,1679,1681],{"class":254,"line":277},[252,1680,1003],{"class":263},[252,1682,1006],{"class":257},[252,1684,1685],{"class":254,"line":286},[252,1686,1011],{"class":257},[252,1688,1689,1691,1693,1695],{"class":254,"line":194},[252,1690,1016],{"class":263},[252,1692,267],{"class":257},[252,1694,600],{"class":270},[252,1696,274],{"class":257},[252,1698,1699,1701,1703,1705],{"class":254,"line":302},[252,1700,1027],{"class":263},[252,1702,267],{"class":257},[252,1704,1032],{"class":270},[252,1706,274],{"class":257},[252,1708,1709,1711,1713,1715],{"class":254,"line":310},[252,1710,1039],{"class":263},[252,1712,267],{"class":257},[252,1714,1044],{"class":270},[252,1716,274],{"class":257},[252,1718,1719,1721,1723,1725],{"class":254,"line":321},[252,1720,1051],{"class":263},[252,1722,267],{"class":257},[252,1724,1056],{"class":270},[252,1726,274],{"class":257},[252,1728,1729,1731,1733],{"class":254,"line":327},[252,1730,1063],{"class":263},[252,1732,267],{"class":257},[252,1734,1068],{"class":270},[252,1736,1737],{"class":254,"line":484},[252,1738,1739],{"class":257},"    },\n",[252,1741,1742],{"class":254,"line":591},[252,1743,1011],{"class":257},[252,1745,1746,1748,1750,1752],{"class":254,"line":1081},[252,1747,1016],{"class":263},[252,1749,267],{"class":257},[252,1751,600],{"class":270},[252,1753,274],{"class":257},[252,1755,1756,1758,1760,1762],{"class":254,"line":1375},[252,1757,1027],{"class":263},[252,1759,267],{"class":257},[252,1761,1032],{"class":270},[252,1763,274],{"class":257},[252,1765,1766,1768,1770,1773],{"class":254,"line":1384},[252,1767,1039],{"class":263},[252,1769,267],{"class":257},[252,1771,1772],{"class":270},"\"Debug micro-service\"",[252,1774,274],{"class":257},[252,1776,1777,1780,1782,1785],{"class":254,"line":1389},[252,1778,1779],{"class":263},"      \"port\"",[252,1781,267],{"class":257},[252,1783,1784],{"class":263},"9230",[252,1786,274],{"class":257},[252,1788,1789,1791,1793,1795],{"class":254,"line":1394},[252,1790,1051],{"class":263},[252,1792,267],{"class":257},[252,1794,1056],{"class":270},[252,1796,274],{"class":257},[252,1798,1799,1801,1803],{"class":254,"line":1399},[252,1800,1063],{"class":263},[252,1802,267],{"class":257},[252,1804,1805],{"class":270},"\"${workspaceFolder}\u002Fmicro-service\u002Fsrc\"\n",[252,1807,1809],{"class":254,"line":1808},18,[252,1810,1073],{"class":257},[252,1812,1814],{"class":254,"line":1813},19,[252,1815,1078],{"class":257},[252,1817,1819],{"class":254,"line":1818},20,[252,1820,330],{"class":257},[30,1822,1823],{},"Once the configuration is added, you can run the two debuggers for each service.",[30,1825,1826],{},[50,1827],{"alt":10,"src":1828},"\u002Fimages\u002Fstart-webapp-debugger.png",[30,1830,1831],{},[50,1832],{"alt":10,"src":1833},"\u002Fimages\u002Fstart-micro-service-debugger.png",[30,1835,1836,1837,1840,1843],{},"Once both debuggers are started, add a breakpoint in each service and go to\n",[69,1838],{"href":719,"rel":1839},[73],[69,1841,719],{"href":719,"rel":1842},[73],".\nThe application will stop successively on each breakpoint.",[30,1845,1846],{},"Your VSCode debugger is now fully configured to work with your Docker services. Congratulations!",[1848,1849,1850],"style",{},"html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--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);}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}html pre.shiki code .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}",{"title":10,"searchDepth":11,"depth":11,"links":1852},[1853,1857,1862],{"id":225,"depth":11,"text":226,"children":1854},[1855,1856],{"id":237,"depth":277,"text":238},{"id":622,"depth":277,"text":623},{"id":731,"depth":11,"text":732,"children":1858},[1859,1860,1861],{"id":735,"depth":277,"text":736},{"id":842,"depth":277,"text":623},{"id":964,"depth":277,"text":965},{"id":1150,"depth":11,"text":1151,"children":1863},[1864,1865,1866],{"id":1154,"depth":277,"text":1155},{"id":1429,"depth":277,"text":623},{"id":1646,"depth":277,"text":1647},"2022-06-10","In my company, we use Docker and Docker Compose to run our Node.js services locally. Recently, I needed to configure and run the VSCode debugger on some of...",{},"\u002Farticles\u002F2022-06-10-how-to-use-vscode-debugger-with-multiple-docker-services",{"title":202,"description":1868},"articles\u002F2022-06-10-how-to-use-vscode-debugger-with-multiple-docker-services",[1874],"dev","k25oDu70V_bSBsuWn05HINg7mLX-vXDTwmPzllNdvPg",[1877,1889,1901,1914,1927,1939,1951,1964,1977,1990,2002,2014,2027,2039,2051,2063,2070,2082,2094,2106,2119,2131,2143,2156,2168,2180],{"id":1878,"title":5,"body":1879,"description":10,"extension":13,"meta":1883,"name":1884,"navigation":16,"path":1885,"readingTime":18,"seo":1886,"stem":1887,"__hash__":1888},"authors\u002Fauthors\u002Falexandre-guillon.md",{"type":7,"value":1880,"toc":1881},[],{"title":10,"searchDepth":11,"depth":11,"links":1882},[],{},"Alexandre Guillon","\u002Fauthors\u002Falexandre-guillon",{"title":5,"description":10},"authors\u002Falexandre-guillon","4tf48mjyjFNqItOHaulICbrjeCyMag1o6801uHeTz98",{"id":1890,"title":5,"body":1891,"description":10,"extension":13,"meta":1895,"name":1896,"navigation":16,"path":1897,"readingTime":18,"seo":1898,"stem":1899,"__hash__":1900},"authors\u002Fauthors\u002Falexis-ablain.md",{"type":7,"value":1892,"toc":1893},[],{"title":10,"searchDepth":11,"depth":11,"links":1894},[],{},"Alexis Ablain","\u002Fauthors\u002Falexis-ablain",{"title":5,"description":10},"authors\u002Falexis-ablain","_SIAtB7f-39e5t3GiJof81NP47s6MGo2n4gaHkTy1uQ",{"id":1902,"title":1903,"body":1904,"description":10,"extension":13,"meta":1908,"name":1909,"navigation":16,"path":1910,"readingTime":18,"seo":1911,"stem":1912,"__hash__":1913},"authors\u002Fauthors\u002Faxel-shaita.md","Engineering Manager",{"type":7,"value":1905,"toc":1906},[],{"title":10,"searchDepth":11,"depth":11,"links":1907},[],{},"Axel Shaïta","\u002Fauthors\u002Faxel-shaita",{"title":1903,"description":10},"authors\u002Faxel-shaita","fK0argUhsBkWLjpTAhY13oYLVzQthcEYkCEdtHWmIgE",{"id":1915,"title":1916,"body":1917,"description":10,"extension":13,"meta":1921,"name":1922,"navigation":16,"path":1923,"readingTime":18,"seo":1924,"stem":1925,"__hash__":1926},"authors\u002Fauthors\u002Fbaptiste-faure.md","Head of Talent Acquisition",{"type":7,"value":1918,"toc":1919},[],{"title":10,"searchDepth":11,"depth":11,"links":1920},[],{},"Baptiste Faure","\u002Fauthors\u002Fbaptiste-faure",{"title":1916,"description":10},"authors\u002Fbaptiste-faure","ELisToYtcgHmgdVWZkCclTPV6exZtfyXqhpx1jjbJHs",{"id":1928,"title":5,"body":1929,"description":10,"extension":13,"meta":1933,"name":1934,"navigation":16,"path":1935,"readingTime":18,"seo":1936,"stem":1937,"__hash__":1938},"authors\u002Fauthors\u002Fbenjamin-bouillot.md",{"type":7,"value":1930,"toc":1931},[],{"title":10,"searchDepth":11,"depth":11,"links":1932},[],{},"Benjamin Bouillot","\u002Fauthors\u002Fbenjamin-bouillot",{"title":5,"description":10},"authors\u002Fbenjamin-bouillot","tbhCFZyfTt7ZM5b5YgqQ2nhgnSTl8BweaQQryc87fHo",{"id":1940,"title":1903,"body":1941,"description":10,"extension":13,"meta":1945,"name":1946,"navigation":16,"path":1947,"readingTime":18,"seo":1948,"stem":1949,"__hash__":1950},"authors\u002Fauthors\u002Fcedric-nicoloso.md",{"type":7,"value":1942,"toc":1943},[],{"title":10,"searchDepth":11,"depth":11,"links":1944},[],{},"Cédric Nicoloso","\u002Fauthors\u002Fcedric-nicoloso",{"title":1903,"description":10},"authors\u002Fcedric-nicoloso","ibSoh4VZYiWYTuLOnZTedaAfcnvet1Q9H7ogW0LgorY",{"id":1952,"title":1953,"body":1954,"description":10,"extension":13,"meta":1958,"name":1959,"navigation":16,"path":1960,"readingTime":18,"seo":1961,"stem":1962,"__hash__":1963},"authors\u002Fauthors\u002Fdavid-touzet.md","Staff Engineer",{"type":7,"value":1955,"toc":1956},[],{"title":10,"searchDepth":11,"depth":11,"links":1957},[],{},"David Touzet","\u002Fauthors\u002Fdavid-touzet",{"title":1953,"description":10},"authors\u002Fdavid-touzet","dHWwnQxb1Ubt-WwXWEODGEo9AFoq1cJUhfg3kdnYSBM",{"id":1965,"title":1966,"body":1967,"description":10,"extension":13,"meta":1971,"name":1972,"navigation":16,"path":1973,"readingTime":18,"seo":1974,"stem":1975,"__hash__":1976},"authors\u002Fauthors\u002Feloise-chizat.md","Data Engineer",{"type":7,"value":1968,"toc":1969},[],{"title":10,"searchDepth":11,"depth":11,"links":1970},[],{},"Eloïse Chizat","\u002Fauthors\u002Feloise-chizat",{"title":1966,"description":10},"authors\u002Feloise-chizat","Utd72Vm9qT4hh2ZbFi6a2_nXw5Wb494Ed_HL1ra5yw8",{"id":1978,"title":1979,"body":1980,"description":10,"extension":13,"meta":1984,"name":1985,"navigation":16,"path":1986,"readingTime":18,"seo":1987,"stem":1988,"__hash__":1989},"authors\u002Fauthors\u002Femmanuel-auclair.md","Staff engineer",{"type":7,"value":1981,"toc":1982},[],{"title":10,"searchDepth":11,"depth":11,"links":1983},[],{},"Emmanuel Auclair","\u002Fauthors\u002Femmanuel-auclair",{"title":1979,"description":10},"authors\u002Femmanuel-auclair","MtsA8THNLEn0dTtYEIQaGwDuf7MjQL55IOeei5gugEg",{"id":1991,"title":5,"body":1992,"description":10,"extension":13,"meta":1996,"name":1997,"navigation":16,"path":1998,"readingTime":18,"seo":1999,"stem":2000,"__hash__":2001},"authors\u002Fauthors\u002Fhoreb-parraud.md",{"type":7,"value":1993,"toc":1994},[],{"title":10,"searchDepth":11,"depth":11,"links":1995},[],{},"Horeb Parraud","\u002Fauthors\u002Fhoreb-parraud",{"title":5,"description":10},"authors\u002Fhoreb-parraud","ajjsnUX4ohZI-ghMdbb92q_taWDkKXVZSLZXoAeLQtg",{"id":2003,"title":1903,"body":2004,"description":10,"extension":13,"meta":2008,"name":2009,"navigation":16,"path":2010,"readingTime":18,"seo":2011,"stem":2012,"__hash__":2013},"authors\u002Fauthors\u002Fhugo-contreras.md",{"type":7,"value":2005,"toc":2006},[],{"title":10,"searchDepth":11,"depth":11,"links":2007},[],{},"Hugo Contreras","\u002Fauthors\u002Fhugo-contreras",{"title":1903,"description":10},"authors\u002Fhugo-contreras","2nc3VMu9ASq9Z6Pwx2-7-Ye991Pww4p-UEDBQFfjF-Q",{"id":2015,"title":2016,"body":2017,"description":10,"extension":13,"meta":2021,"name":2022,"navigation":16,"path":2023,"readingTime":18,"seo":2024,"stem":2025,"__hash__":2026},"authors\u002Fauthors\u002Fjulien-tassin.md","Head of Engineering",{"type":7,"value":2018,"toc":2019},[],{"title":10,"searchDepth":11,"depth":11,"links":2020},[],{},"Julien Tassin","\u002Fauthors\u002Fjulien-tassin",{"title":2016,"description":10},"authors\u002Fjulien-tassin","iUIHI7SITje38Jh9X9uvYs4-VsHx4eCdt6hAlyLFG_o",{"id":2028,"title":5,"body":2029,"description":10,"extension":13,"meta":2033,"name":2034,"navigation":16,"path":2035,"readingTime":18,"seo":2036,"stem":2037,"__hash__":2038},"authors\u002Fauthors\u002Flaurent-renard.md",{"type":7,"value":2030,"toc":2031},[],{"title":10,"searchDepth":11,"depth":11,"links":2032},[],{},"Laurent Renard","\u002Fauthors\u002Flaurent-renard",{"title":5,"description":10},"authors\u002Flaurent-renard","5BP7Ed-pt1SQHjh0UJ1XUrlLTcdlFaDoKBCP4deHq8A",{"id":2040,"title":5,"body":2041,"description":10,"extension":13,"meta":2045,"name":2046,"navigation":16,"path":2047,"readingTime":18,"seo":2048,"stem":2049,"__hash__":2050},"authors\u002Fauthors\u002Fleo-martin.md",{"type":7,"value":2042,"toc":2043},[],{"title":10,"searchDepth":11,"depth":11,"links":2044},[],{},"Léo Martin","\u002Fauthors\u002Fleo-martin",{"title":5,"description":10},"authors\u002Fleo-martin","eYxCHkRgbGDV7shKdTA9s7Tu0zGV4yDGFoKR5MHQntY",{"id":2052,"title":5,"body":2053,"description":10,"extension":13,"meta":2057,"name":2058,"navigation":16,"path":2059,"readingTime":18,"seo":2060,"stem":2061,"__hash__":2062},"authors\u002Fauthors\u002Floic-bousquet.md",{"type":7,"value":2054,"toc":2055},[],{"title":10,"searchDepth":11,"depth":11,"links":2056},[],{},"Loïc Bousquet","\u002Fauthors\u002Floic-bousquet",{"title":5,"description":10},"authors\u002Floic-bousquet","ko12qZwiGL8XNjAoy9oWypPkIjr29Pbq7vhdtgldqeQ",{"id":4,"title":5,"body":2064,"description":10,"extension":13,"meta":2068,"name":15,"navigation":16,"path":17,"readingTime":18,"seo":2069,"stem":20,"__hash__":21},{"type":7,"value":2065,"toc":2066},[],{"title":10,"searchDepth":11,"depth":11,"links":2067},[],{},{"title":5,"description":10},{"id":2071,"title":1966,"body":2072,"description":10,"extension":13,"meta":2076,"name":2077,"navigation":16,"path":2078,"readingTime":18,"seo":2079,"stem":2080,"__hash__":2081},"authors\u002Fauthors\u002Fmaud-lelu.md",{"type":7,"value":2073,"toc":2074},[],{"title":10,"searchDepth":11,"depth":11,"links":2075},[],{},"Maud Lélu","\u002Fauthors\u002Fmaud-lelu",{"title":1966,"description":10},"authors\u002Fmaud-lelu","MMbsCKuE41OMHusrl12FIEsI-Trx7l8Nn_ANhvj2_y4",{"id":2083,"title":1903,"body":2084,"description":10,"extension":13,"meta":2088,"name":2089,"navigation":16,"path":2090,"readingTime":18,"seo":2091,"stem":2092,"__hash__":2093},"authors\u002Fauthors\u002Fnicolas-poirier.md",{"type":7,"value":2085,"toc":2086},[],{"title":10,"searchDepth":11,"depth":11,"links":2087},[],{},"Nicolas Poirier","\u002Fauthors\u002Fnicolas-poirier",{"title":1903,"description":10},"authors\u002Fnicolas-poirier","dXrJkYo8az4SN_D23aYc3fQ7z8s1dR2a0lt1ogjAjJs",{"id":2095,"title":1903,"body":2096,"description":10,"extension":13,"meta":2100,"name":2101,"navigation":16,"path":2102,"readingTime":18,"seo":2103,"stem":2104,"__hash__":2105},"authors\u002Fauthors\u002Fraphael-sauget.md",{"type":7,"value":2097,"toc":2098},[],{"title":10,"searchDepth":11,"depth":11,"links":2099},[],{},"Raphaël Sauget","\u002Fauthors\u002Fraphael-sauget",{"title":1903,"description":10},"authors\u002Fraphael-sauget","Uri9bcq0QDuxRA0PbBoNtu7p_5L3dALu4kzcXVW0xyM",{"id":2107,"title":2108,"body":2109,"description":10,"extension":13,"meta":2113,"name":2114,"navigation":16,"path":2115,"readingTime":18,"seo":2116,"stem":2117,"__hash__":2118},"authors\u002Fauthors\u002Fromain-koenig.md","Co-funder & Head of innovation",{"type":7,"value":2110,"toc":2111},[],{"title":10,"searchDepth":11,"depth":11,"links":2112},[],{},"Romain Koenig","\u002Fauthors\u002Fromain-koenig",{"title":2108,"description":10},"authors\u002Fromain-koenig","uyS8--eG2_ezyqRABcJnMJmQKKuSArhPWd14aUvFeEw",{"id":2120,"title":1903,"body":2121,"description":10,"extension":13,"meta":2125,"name":2126,"navigation":16,"path":2127,"readingTime":18,"seo":2128,"stem":2129,"__hash__":2130},"authors\u002Fauthors\u002Fromaric-juniet.md",{"type":7,"value":2122,"toc":2123},[],{"title":10,"searchDepth":11,"depth":11,"links":2124},[],{},"Romaric Juniet","\u002Fauthors\u002Fromaric-juniet",{"title":1903,"description":10},"authors\u002Fromaric-juniet","4Zb2artgT-eo-PHLXi3xi4d5t7s6PfhUxeSfXIikSUY",{"id":2132,"title":5,"body":2133,"description":10,"extension":13,"meta":2137,"name":2138,"navigation":16,"path":2139,"readingTime":18,"seo":2140,"stem":2141,"__hash__":2142},"authors\u002Fauthors\u002Fstanyslas-bres.md",{"type":7,"value":2134,"toc":2135},[],{"title":10,"searchDepth":11,"depth":11,"links":2136},[],{},"Stanyslas Bres","\u002Fauthors\u002Fstanyslas-bres",{"title":5,"description":10},"authors\u002Fstanyslas-bres","Xa0SahETuiN4q1jrmR2ych3moAqcZ2LbU7vSfEt2RuU",{"id":2144,"title":2145,"body":2146,"description":10,"extension":13,"meta":2150,"name":2151,"navigation":16,"path":2152,"readingTime":18,"seo":2153,"stem":2154,"__hash__":2155},"authors\u002Fauthors\u002Ftalent-acquisition.md","Talent Acquisition",{"type":7,"value":2147,"toc":2148},[],{"title":10,"searchDepth":11,"depth":11,"links":2149},[],{},"Équipe Talent Acquisition","\u002Fauthors\u002Ftalent-acquisition",{"description":10},"authors\u002Ftalent-acquisition","doDfE76txftQ4wIiKjJoDmSpyzSKk0tzlgVAp6-opAY",{"id":2157,"title":5,"body":2158,"description":10,"extension":13,"meta":2162,"name":2163,"navigation":16,"path":2164,"readingTime":18,"seo":2165,"stem":2166,"__hash__":2167},"authors\u002Fauthors\u002Fvictor-borg.md",{"type":7,"value":2159,"toc":2160},[],{"title":10,"searchDepth":11,"depth":11,"links":2161},[],{},"Victor Borg","\u002Fauthors\u002Fvictor-borg",{"title":5,"description":10},"authors\u002Fvictor-borg","-Za-JweoiP6hyclue_WkxMXdRUDTczPGlJf6AZckjUc",{"id":2169,"title":5,"body":2170,"description":10,"extension":13,"meta":2174,"name":2175,"navigation":16,"path":2176,"readingTime":18,"seo":2177,"stem":2178,"__hash__":2179},"authors\u002Fauthors\u002Fvirgil-roger.md",{"type":7,"value":2171,"toc":2172},[],{"title":10,"searchDepth":11,"depth":11,"links":2173},[],{},"Virgil Roger","\u002Fauthors\u002Fvirgil-roger",{"title":5,"description":10},"authors\u002Fvirgil-roger","DfVFe5j0bCgXeEr381ZYOM5DP4m-pWb93J9-m_muKJ0",{"id":2181,"title":5,"body":2182,"description":10,"extension":13,"meta":2186,"name":2187,"navigation":16,"path":2188,"readingTime":18,"seo":2189,"stem":2190,"__hash__":2191},"authors\u002Fauthors\u002Fyukan-zhao.md",{"type":7,"value":2183,"toc":2184},[],{"title":10,"searchDepth":11,"depth":11,"links":2185},[],{},"Yukan Zhao","\u002Fauthors\u002Fyukan-zhao",{"title":5,"description":10},"authors\u002Fyukan-zhao","LRPHugtAJnWHsmHxy9_SR5Zas_C5p-GR_uHEs1Fhk_E",1778159244807]