{"id":229,"date":"2026-10-21T14:21:01","date_gmt":"2026-10-21T14:21:01","guid":{"rendered":"https:\/\/devdojo.co.in\/?p=229"},"modified":"2026-10-21T14:21:03","modified_gmt":"2026-10-21T14:21:03","slug":"devops-series-part-1-what-is-devops-ci-cd","status":"publish","type":"post","link":"https:\/\/devdojo.co.in\/index.php\/2026\/10\/21\/devops-series-part-1-what-is-devops-ci-cd\/","title":{"rendered":"DevOps CI\/CD Part 1: What Is DevOps and How Does CI\/CD Work?"},"content":{"rendered":"\n<div class=\"dd-post\">\n<style>\n.single article:has(.dd-hero) .entry-media{display:none}\n.dd-post{--navy:#0b1020;--blue:#3178c6;--violet:#7c5cff;--ink:#1f2433;--muted:#5b6275;--line:#e3e6ef;font-size:17px;line-height:1.75;color:var(--ink)}\n.dd-post h2{margin:2.2em 0 .6em;font-size:1.6em;line-height:1.3;scroll-margin-top:90px}\n.dd-post h3{margin:1.6em 0 .5em;font-size:1.22em;scroll-margin-top:90px}\n.dd-post a{color:var(--blue);text-decoration:underline;text-underline-offset:3px}\n.dd-post pre{background:#0f1430;color:#e6e9f5;padding:18px 20px;border-radius:12px;overflow-x:auto;line-height:1.6;border:1px solid #232a52;margin:1.2em 0;font-size:14.5px !important}\n.dd-post pre code{font-size:1em !important;background:none;color:inherit;padding:0;font-family:\"JetBrains Mono\",\"Fira Code\",Consolas,Menlo,monospace;white-space:pre}\n.dd-post :not(pre)>code{background:#eef1fb;color:#2b3a8f;padding:2px 6px;border-radius:5px;font-size:.9em}\n.dd-post .dd-file{display:inline-block;background:#151b3b;color:#c9d1ff;font:600 13px\/1 \"JetBrains Mono\",Consolas,monospace;padding:7px 12px;border-radius:8px 8px 0 0;margin:1em 0 -1.2em;position:relative}\n.dd-post .dd-hero{margin:0 0 1.6em;border-radius:16px;overflow:hidden;box-shadow:0 10px 30px rgba(11,16,32,.25)}\n.dd-post .dd-hero svg{display:block;width:100%;height:auto}\n.dd-post .dd-hero .node{transition:transform .25s,filter .25s;transform-box:fill-box;transform-origin:center;cursor:pointer}\n.dd-post .dd-hero .node:hover{transform:scale(1.08);filter:drop-shadow(0 0 10px #7c5cff)}\n.dd-post .dd-series{display:inline-flex;align-items:center;gap:8px;background:#151b3b;color:#dfe3ff;border-radius:999px;padding:6px 14px;font-size:.88em;font-weight:600;margin:0 0 .8em}\n.dd-post .dd-series span{background:var(--violet);color:#fff;border-radius:999px;padding:2px 10px}\n.dd-post .dd-prereq{font-size:.96em;color:var(--muted);border-left:3px solid var(--line);padding-left:12px;margin:.6em 0 1.2em}\n.dd-post .dd-summary{background:linear-gradient(135deg,#eef3ff,#f4efff);border:1px solid #d6dcf5;border-left:5px solid var(--violet);border-radius:12px;padding:18px 22px;margin:1.4em 0}\n.dd-post .dd-summary strong.lbl{display:block;font-size:1.05em;margin-bottom:6px;color:#3a2fa0}\n.dd-post .dd-summary ul{margin:.3em 0 0 1.1em}\n.dd-post .dd-toc{background:#f8f9fc;border:1px solid var(--line);border-radius:12px;padding:16px 22px;margin:1.4em 0}\n.dd-post .dd-toc ol{margin:.4em 0 0 1.2em;columns:2;column-gap:28px}\n.dd-post .dd-toc li{break-inside:avoid;margin:.15em 0}\n@media(max-width:640px){.dd-post .dd-toc ol{columns:1}}\n.dd-post .dd-tip,.dd-post .dd-note,.dd-post .dd-warn{border-radius:10px;padding:14px 18px;margin:1.3em 0}\n.dd-post .dd-tip{background:#ecfbf3;border-left:4px solid #1f9d61}\n.dd-post .dd-note{background:#eef4ff;border-left:4px solid var(--blue)}\n.dd-post .dd-warn{background:#fff6e8;border-left:4px solid #e08a00}\n.dd-post .dd-cards{display:grid;grid-template-columns:repeat(auto-fit,minmax(210px,1fr));gap:14px;margin:1.3em 0}\n.dd-post .dd-card{border:1px solid var(--line);border-radius:12px;padding:14px 16px;background:#fff;box-shadow:0 2px 8px rgba(20,30,70,.05)}\n.dd-post .dd-card b{display:block;color:#3a2fa0;margin-bottom:4px}\n.dd-post table{width:100%;border-collapse:collapse;margin:1.3em 0;font-size:.95em}\n.dd-post th,.dd-post td{border:1px solid var(--line);padding:10px 12px;text-align:left;vertical-align:top}\n.dd-post th{background:#151b3b;color:#fff}\n.dd-post tr:nth-child(even) td{background:#f8f9fc}\n.dd-post .dd-tablewrap{overflow-x:auto}\n.dd-post figure{margin:1.6em 0;text-align:center}\n.dd-post figure svg{width:100%;height:auto;border-radius:12px}\n.dd-post figcaption{font-size:.9em;color:var(--muted);margin-top:8px}\n.dd-post details{border:1px solid var(--line);border-radius:10px;padding:12px 16px;margin:.7em 0;background:#fff}\n.dd-post details summary{cursor:pointer;font-weight:600}\n.dd-post details[open] summary{margin-bottom:8px;color:#3a2fa0}\n.dd-post .dd-roadmap{border:2px solid #d6dcf5;background:#fbfbff}\n.dd-post .dd-roadmap h4{margin:1em 0 .3em;color:#151b3b;font-size:1em;text-transform:uppercase;letter-spacing:.04em}\n.dd-post .dd-roadmap ol{margin:.2em 0 .6em 1.4em;padding:0}\n.dd-post .dd-roadmap li{margin:.2em 0}\n.dd-post .dd-roadmap .here{background:var(--violet);color:#fff;border-radius:999px;padding:1px 9px;font-size:.8em;font-weight:700;margin-left:6px}\n.dd-post .dd-roadmap .soon{color:#8a90a6;font-size:.82em;margin-left:6px}\n.dd-post .dd-tabs{border:1px solid var(--line);border-radius:12px;padding:6px 16px 16px;margin:1.4em 0;background:#fbfbfe}\n.dd-post .dd-tabs>input{position:absolute;opacity:0;pointer-events:none}\n.dd-post .dd-tabs .labels label{display:inline-block;padding:8px 16px;margin:10px 6px 0 0;border-radius:999px;border:1px solid #cfd5ea;cursor:pointer;font-weight:600;font-size:.95em;background:#fff;transition:background .2s}\n.dd-post .dd-tabs .labels label:hover{border-color:var(--violet)}\n.dd-post .dd-tabs .panel{display:none;margin-top:12px}\n.dd-post .dd-tabs #ti1:checked~.labels label[for=ti1],.dd-post .dd-tabs #ti2:checked~.labels label[for=ti2],.dd-post .dd-tabs #ti3:checked~.labels label[for=ti3],.dd-post .dd-tabs #ti4:checked~.labels label[for=ti4]{background:var(--violet);color:#fff;border-color:var(--violet)}\n.dd-post .dd-tabs #ti1:checked~.p1,.dd-post .dd-tabs #ti2:checked~.p2,.dd-post .dd-tabs #ti3:checked~.p3,.dd-post .dd-tabs #ti4:checked~.p4{display:block}\n.dd-post .dd-tabs #ti1:focus-visible~.labels label[for=ti1],.dd-post .dd-tabs #ti2:focus-visible~.labels label[for=ti2],.dd-post .dd-tabs #ti3:focus-visible~.labels label[for=ti3],.dd-post .dd-tabs #ti4:focus-visible~.labels label[for=ti4]{outline:2px solid var(--blue);outline-offset:2px}\n.dd-post .dd-cta{background:linear-gradient(135deg,#0b1020,#151b3b);color:#e8ebff;border-radius:16px;padding:24px 26px;margin:2em 0;text-align:center}\n.dd-post .dd-cta h3{color:#fff;margin-top:0}\n.dd-post .dd-cta a{color:#a99bff}\n.dd-post .dd-vsc{position:relative;margin:1.5em 0;border-radius:12px;overflow:hidden;background:#1e1e1e;border:1px solid #2b2b2b;box-shadow:0 14px 34px rgba(0,0,0,.28);font-family:\"Segoe UI\",system-ui,sans-serif}\n.dd-post .dd-vsc>input{position:absolute;opacity:0;pointer-events:none}\n.dd-post .dd-vsc-bar{display:flex;align-items:center;gap:12px;background:#323233;color:#cccccc;font-size:12.5px;padding:8px 12px}\n.dd-post .dd-dots{display:inline-flex;gap:7px}.dd-post .dd-dots i{width:12px;height:12px;border-radius:50%;background:#ff5f57;display:block}.dd-post .dd-dots i:nth-child(2){background:#febc2e}.dd-post .dd-dots i:nth-child(3){background:#28c840}\n.dd-post .dd-vsc-title{flex:1;text-align:center;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;padding-right:50px;opacity:.85}\n.dd-post .dd-vsc-tabs{display:flex;align-items:stretch;background:#252526;border-bottom:1px solid #1e1e1e;overflow-x:auto}\n.dd-post .dd-vsc-tabs label{display:flex;align-items:center;gap:7px;padding:9px 16px;color:#969696;font-size:13px;cursor:pointer;background:#2d2d2d;border-right:1px solid #252526;border-top:1px solid transparent;white-space:nowrap;margin:0;transition:color .15s}\n.dd-post .dd-vsc-tabs label:hover{color:#e0e0e0}\n.dd-post .dd-vsc-tabs .ic{font:700 9.5px\/1 Consolas,monospace;padding:3px 4px;border-radius:3px;color:#1e1e1e}\n.dd-post .ic.py{background:#ffd43b}.dd-post .ic.js{background:#f1e05a}.dd-post .ic.sh{background:#89e051}\n.dd-post .dd-vsc-tabs label.run{margin-left:auto;background:transparent;border:0;color:#89d185;font-weight:600;display:none}\n.dd-post .dd-vsc-tabs label.run:hover{color:#b5f0b0;background:#2a2d2e}\n.dd-post .dd-vsc-pane{display:none}\n.dd-post .dd-vsc>.f1:checked~.dd-vsc-tabs .t1,.dd-post .dd-vsc>.f2:checked~.dd-vsc-tabs .t2,.dd-post .dd-vsc>.f3:checked~.dd-vsc-tabs .t3{background:#1e1e1e;color:#ffffff;border-top-color:#3178c6}\n.dd-post .dd-vsc>.f1:checked~.p1,.dd-post .dd-vsc>.f2:checked~.p2,.dd-post .dd-vsc>.f3:checked~.p3{display:block}\n.dd-post .dd-vsc>.f1:checked~.dd-vsc-tabs .run1,.dd-post .dd-vsc>.f2:checked~.dd-vsc-tabs .run2,.dd-post .dd-vsc>.f3:checked~.dd-vsc-tabs .run3{display:flex}\n.dd-post .dd-vsc>.f1:focus-visible~.dd-vsc-tabs .t1,.dd-post .dd-vsc>.f2:focus-visible~.dd-vsc-tabs .t2,.dd-post .dd-vsc>.f3:focus-visible~.dd-vsc-tabs .t3,.dd-post .dd-vsc>input[type=checkbox]:focus-visible~.dd-vsc-tabs .run{outline:2px solid #3178c6;outline-offset:-2px}\n.dd-post .dd-vsc-crumbs{background:#1e1e1e;color:#a9a9a9;font-size:12px;padding:5px 16px 2px}\n.dd-post .dd-vsc pre.dd-vsc-code{background:#1e1e1e;color:#d4d4d4;border:0;border-radius:0;margin:0;padding:8px 0 14px;counter-reset:ln;line-height:1.62;overflow-x:auto}\n.dd-post .dd-vsc pre code{font-family:Consolas,\"JetBrains Mono\",\"Fira Code\",Menlo,monospace;color:inherit;background:none;white-space:pre}\n.dd-post .dd-vsc .l{display:inline-block;min-width:100%;padding-right:18px;box-sizing:border-box}\n.dd-post .dd-vsc .l::before{counter-increment:ln;content:counter(ln);display:inline-block;width:3.2em;padding-right:1.4em;text-align:right;color:#6e7681;user-select:none;-webkit-user-select:none}\n.dd-post .dd-vsc .l:hover{background:#2a2d2e}.dd-post .dd-vsc .l:hover::before{color:#c6c6c6}\n.dd-post .dd-vsc .k,.dd-post .dd-vsc .kn{color:#c586c0}.dd-post .dd-vsc .kc{color:#569cd6}.dd-post .dd-vsc .s{color:#ce9178}.dd-post .dd-vsc .c{color:#6a9955}.dd-post .dd-vsc .m{color:#b5cea8}.dd-post .dd-vsc .nf{color:#dcdcaa}.dd-post .dd-vsc .nc{color:#4ec9b0}.dd-post .dd-vsc .nb{color:#4ec9b0}.dd-post .dd-vsc .nd{color:#dcdcaa}.dd-post .dd-vsc .n{color:#9cdcfe}.dd-post .dd-vsc .o{color:#d4d4d4}.dd-post .dd-vsc .gp{color:#89d185;user-select:none;-webkit-user-select:none}\n.dd-post .dd-vsc-term{display:none;border-top:1px solid #3c3c3c;background:#181818}\n.dd-post .dd-vsc>.r1:checked~.p1 .dd-vsc-term,.dd-post .dd-vsc>.r2:checked~.p2 .dd-vsc-term,.dd-post .dd-vsc>.r3:checked~.p3 .dd-vsc-term{display:block;animation:ddterm .35s ease-out}\n@keyframes ddterm{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}\n.dd-post .dd-term-head{display:flex;gap:18px;align-items:center;font-size:11px;letter-spacing:.06em;color:#8b8b8b;padding:7px 16px 0}\n.dd-post .dd-term-head span:first-child{color:#e7e7e7;border-bottom:1px solid #e7e7e7;padding-bottom:4px}\n.dd-post .dd-term-head .dd-term-note{margin-left:auto;letter-spacing:0;text-transform:none;color:#d7ba7d;border:0;font-size:11.5px}\n.dd-post .dd-vsc-term pre{background:#181818;color:#cccccc;border:0;margin:0;padding:10px 16px 14px;border-radius:0}\n.dd-post .dd-vsc-status{display:flex;flex-wrap:wrap;gap:4px 14px;background:#007acc;color:#fff;font-size:11.5px;padding:4px 12px}\n.dd-post .dd-vsc-status .sp{flex:1}\n.dd-post .dd-vsc-termonly pre.dd-vsc-code{background:#181818;padding:12px 16px}\n@media(max-width:640px){.dd-post .dd-vsc-title{padding-right:0;text-align:left}.dd-post .dd-vsc-status span:nth-child(n+4){display:none}.dd-post .dd-vsc .l::before{width:2.2em;padding-right:1em}}\n.dd-post .dd-vsc-hint{font-size:.93em;color:var(--muted);margin-top:-.6em}\n.dd-post .dd-next{border:1px dashed var(--violet);border-radius:12px;padding:16px 20px;margin:1.6em 0;background:#f7f4ff}\n.dd-post .ic.yml{background:#cb3837;color:#fff}\n<\/style>\n\n<div class=\"dd-hero\">\n<svg viewBox=\"0 0 1200 520\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" role=\"img\" aria-label=\"DevOps CI\/CD series Part 1 banner: the DevOps infinity loop of plan, code, build, test, release, deploy, operate and monitor, next to a small CI\/CD pipeline\">\n<defs>\n<linearGradient id=\"ddbg\" x1=\"0\" y1=\"0\" x2=\"1\" y2=\"1\"><stop offset=\"0\" stop-color=\"#0b1020\"\/><stop offset=\"1\" stop-color=\"#151b3b\"\/><\/linearGradient>\n<linearGradient id=\"ddac\" x1=\"0\" y1=\"0\" x2=\"1\" y2=\"0\"><stop offset=\"0\" stop-color=\"#3178c6\"\/><stop offset=\"1\" stop-color=\"#7c5cff\"\/><\/linearGradient>\n<radialGradient id=\"ddglow\" cx=\".5\" cy=\".5\" r=\".5\"><stop offset=\"0\" stop-color=\"#7c5cff\" stop-opacity=\".45\"\/><stop offset=\"1\" stop-color=\"#7c5cff\" stop-opacity=\"0\"\/><\/radialGradient>\n<\/defs>\n<rect x=\"0\" y=\"-60\" width=\"1200\" height=\"640\" fill=\"url(#ddbg)\"\/>\n<circle cx=\"900\" cy=\"300\" r=\"270\" fill=\"url(#ddglow)\"\/>\n<g opacity=\".12\" stroke=\"#9fb2ff\"><path d=\"M0 100H1200M0 200H1200M0 300H1200M0 400H1200M200 0V520M400 0V520M600 0V520M800 0V520M1000 0V520\"\/><\/g>\n<rect x=\"60\" y=\"46\" width=\"128\" height=\"38\" rx=\"19\" fill=\"url(#ddac)\"\/>\n<text x=\"124\" y=\"71\" text-anchor=\"middle\" font-family=\"Segoe UI,Arial,sans-serif\" font-size=\"18\" font-weight=\"700\" fill=\"#fff\">PART 1<\/text>\n<text x=\"204\" y=\"71\" font-family=\"Segoe UI,Arial,sans-serif\" font-size=\"18\" fill=\"#aab4e8\">DevOps CI\/CD Series \u00b7 DevDojo<\/text>\n<text x=\"60\" y=\"148\" font-family=\"Segoe UI,Arial,sans-serif\" font-size=\"52\" font-weight=\"800\" fill=\"#ffffff\">What Is DevOps?<\/text>\n<text x=\"60\" y=\"206\" font-family=\"Segoe UI,Arial,sans-serif\" font-size=\"52\" font-weight=\"800\" fill=\"#ffffff\">How CI\/CD Works<\/text>\n<text x=\"60\" y=\"250\" font-family=\"Segoe UI,Arial,sans-serif\" font-size=\"24\" fill=\"#c9d1ff\">From git push to production, automatically and safely<\/text>\n<path id=\"ddinf\" d=\"M900 300 C 960 200, 1120 200, 1120 300 C 1120 400, 960 400, 900 300 C 840 200, 680 200, 680 300 C 680 400, 840 400, 900 300 Z\" fill=\"none\" stroke=\"url(#ddac)\" stroke-width=\"6\" opacity=\".9\"\/>\n<text x=\"770\" y=\"308\" text-anchor=\"middle\" font-family=\"Segoe UI,Arial,sans-serif\" font-size=\"26\" font-weight=\"800\" fill=\"#ffffff\">DEV<\/text>\n<text x=\"1030\" y=\"308\" text-anchor=\"middle\" font-family=\"Segoe UI,Arial,sans-serif\" font-size=\"26\" font-weight=\"800\" fill=\"#ffffff\">OPS<\/text>\n<g class=\"node\"><rect x=\"700\" y=\"176\" width=\"96\" height=\"34\" rx=\"17\" fill=\"#1b2250\" stroke=\"#3178c6\" stroke-width=\"2\"\/><text x=\"748\" y=\"199\" text-anchor=\"middle\" font-family=\"Segoe UI,Arial,sans-serif\" font-size=\"16\" font-weight=\"700\" fill=\"#fff\">\ud83d\udcdd Plan<\/text><\/g>\n<g class=\"node\"><rect x=\"606\" y=\"283\" width=\"68\" height=\"34\" rx=\"17\" fill=\"#1b2250\" stroke=\"#3178c6\" stroke-width=\"2\"\/><text x=\"640\" y=\"306\" text-anchor=\"middle\" font-family=\"Segoe UI,Arial,sans-serif\" font-size=\"15\" font-weight=\"700\" fill=\"#fff\">Code<\/text><\/g>\n<g class=\"node\"><rect x=\"700\" y=\"390\" width=\"96\" height=\"34\" rx=\"17\" fill=\"#1b2250\" stroke=\"#3178c6\" stroke-width=\"2\"\/><text x=\"748\" y=\"413\" text-anchor=\"middle\" font-family=\"Segoe UI,Arial,sans-serif\" font-size=\"16\" font-weight=\"700\" fill=\"#fff\">\ud83d\udd28 Build<\/text><\/g>\n<g class=\"node\"><rect x=\"822\" y=\"345\" width=\"78\" height=\"34\" rx=\"17\" fill=\"#1b2250\" stroke=\"#3178c6\" stroke-width=\"2\"\/><text x=\"861\" y=\"368\" text-anchor=\"middle\" font-family=\"Segoe UI,Arial,sans-serif\" font-size=\"16\" font-weight=\"700\" fill=\"#fff\">\u2705 Test<\/text><\/g>\n<g class=\"node\"><rect x=\"900\" y=\"221\" width=\"96\" height=\"34\" rx=\"17\" fill=\"#1b2250\" stroke=\"#7c5cff\" stroke-width=\"2\"\/><text x=\"948\" y=\"244\" text-anchor=\"middle\" font-family=\"Segoe UI,Arial,sans-serif\" font-size=\"16\" font-weight=\"700\" fill=\"#fff\">\ud83d\udce6 Release<\/text><\/g>\n<g class=\"node\"><rect x=\"1004\" y=\"176\" width=\"100\" height=\"34\" rx=\"17\" fill=\"#1b2250\" stroke=\"#7c5cff\" stroke-width=\"2\"\/><text x=\"1054\" y=\"199\" text-anchor=\"middle\" font-family=\"Segoe UI,Arial,sans-serif\" font-size=\"16\" font-weight=\"700\" fill=\"#fff\">\ud83d\ude80 Deploy<\/text><\/g>\n<g class=\"node\"><rect x=\"1100\" y=\"283\" width=\"88\" height=\"34\" rx=\"17\" fill=\"#1b2250\" stroke=\"#7c5cff\" stroke-width=\"2\"\/><text x=\"1144\" y=\"306\" text-anchor=\"middle\" font-family=\"Segoe UI,Arial,sans-serif\" font-size=\"15\" font-weight=\"700\" fill=\"#fff\">Operate<\/text><\/g>\n<g class=\"node\"><rect x=\"1004\" y=\"390\" width=\"108\" height=\"34\" rx=\"17\" fill=\"#1b2250\" stroke=\"#7c5cff\" stroke-width=\"2\"\/><text x=\"1058\" y=\"413\" text-anchor=\"middle\" font-family=\"Segoe UI,Arial,sans-serif\" font-size=\"16\" font-weight=\"700\" fill=\"#fff\">\ud83d\udcc8 Monitor<\/text><\/g>\n<circle r=\"9\" fill=\"#ffffff\"><animateMotion dur=\"6s\" repeatCount=\"indefinite\"><mpath href=\"#ddinf\"\/><\/animateMotion><\/circle>\n<circle r=\"7\" fill=\"#7c5cff\"><animateMotion dur=\"6s\" begin=\"3s\" repeatCount=\"indefinite\"><mpath href=\"#ddinf\"\/><\/animateMotion><\/circle>\n<path id=\"ddpipe\" d=\"M80 380 H540\" fill=\"none\" stroke=\"url(#ddac)\" stroke-width=\"3\" stroke-dasharray=\"8 8\" opacity=\".7\"\/>\n<g class=\"node\"><rect x=\"60\" y=\"358\" width=\"118\" height=\"44\" rx=\"12\" fill=\"url(#ddac)\"\/><text x=\"119\" y=\"386\" text-anchor=\"middle\" font-family=\"Segoe UI,Arial,sans-serif\" font-size=\"16\" font-weight=\"800\" fill=\"#fff\">git push<\/text><\/g>\n<g class=\"node\"><rect x=\"200\" y=\"358\" width=\"96\" height=\"44\" rx=\"12\" fill=\"#0b1020\" stroke=\"#7c5cff\" stroke-width=\"2\"\/><text x=\"248\" y=\"386\" text-anchor=\"middle\" font-family=\"Segoe UI,Arial,sans-serif\" font-size=\"16\" font-weight=\"700\" fill=\"#c9d1ff\">\u2714 build<\/text><\/g>\n<g class=\"node\"><rect x=\"318\" y=\"358\" width=\"96\" height=\"44\" rx=\"12\" fill=\"#0b1020\" stroke=\"#7c5cff\" stroke-width=\"2\"\/><text x=\"366\" y=\"386\" text-anchor=\"middle\" font-family=\"Segoe UI,Arial,sans-serif\" font-size=\"16\" font-weight=\"700\" fill=\"#c9d1ff\">\u2714 test<\/text><\/g>\n<g class=\"node\"><rect x=\"436\" y=\"358\" width=\"110\" height=\"44\" rx=\"12\" fill=\"#0b1020\" stroke=\"#7c5cff\" stroke-width=\"2\"\/><text x=\"491\" y=\"386\" text-anchor=\"middle\" font-family=\"Segoe UI,Arial,sans-serif\" font-size=\"16\" font-weight=\"700\" fill=\"#c9d1ff\">\ud83d\ude80 deploy<\/text><\/g>\n<circle r=\"6\" fill=\"#3178c6\"><animateMotion dur=\"3s\" repeatCount=\"indefinite\"><mpath href=\"#ddpipe\"\/><\/animateMotion><\/circle>\n<text x=\"60\" y=\"440\" font-family=\"Segoe UI,Arial,sans-serif\" font-size=\"17\" fill=\"#aab4e8\">Every change \u2192 automatically built, tested and shipped<\/text>\n<text x=\"60\" y=\"505\" font-family=\"Segoe UI,Arial,sans-serif\" font-size=\"16\" fill=\"#7f89b5\">devdojo.co.in \u00b7 Beginner friendly \u00b7 Node.js + Python examples<\/text>\n<\/svg>\n<\/div>\n\n<div class=\"dd-series\">Series: DevOps CI\/CD <span>Part 1 of 30<\/span><\/div>\n<p class=\"dd-prereq\"><strong>What you should know first:<\/strong> this is the first part, so no earlier part is needed. It helps if you can open a terminal, run a few commands and make a Git commit. Basic JavaScript or Python is enough for the code examples.<\/p>\n\n<p>You have probably seen job posts asking for \u201cDevOps experience\u201d or \u201cCI\/CD pipelines\u201d, and wondered what those words really mean. In this first part of the DevOps CI\/CD series you will learn, in simple words, <strong>what is DevOps<\/strong>, why companies care about it, and how a <strong>CI\/CD pipeline<\/strong> turns every <code>git push<\/code> into tested, ready-to-ship software. Then you will build a tiny pipeline yourself: first as a shell script on your laptop, then as a real GitHub Actions workflow that runs in the cloud.<\/p>\n\n<div class=\"dd-summary\">\n<strong class=\"lbl\">Quick Summary<\/strong>\n<ul>\n<li><strong>DevOps<\/strong> is a way of working where developers (Dev) and operations (Ops) act as one team and <strong>automate<\/strong> the path from code to production.<\/li>\n<li><strong>CI (Continuous Integration)<\/strong> = merge small changes often, and automatically build and test every change.<\/li>\n<li><strong>CD<\/strong> means <strong>Continuous Delivery<\/strong> (always ready to release, a human approves) or <strong>Continuous Deployment<\/strong> (every passing change goes live automatically).<\/li>\n<li>A <strong>pipeline<\/strong> is a list of automated stages (build \u2192 test \u2192 package \u2192 deploy). If one stage fails, the pipeline stops and tells you.<\/li>\n<li>Good DevOps is measured with the <strong>DORA metrics<\/strong>: how often you deploy, how fast changes reach users, how often they fail, and how fast you recover.<\/li>\n<\/ul>\n<\/div>\n\n<details class=\"dd-roadmap\">\n<summary>Full DevOps CI\/CD roadmap (30 parts)<\/summary>\n<h4>Beginner<\/h4>\n<ol start=\"1\">\n<li>What Is DevOps and How Does CI\/CD Work? <span class=\"here\">You are here<\/span><\/li>\n<li>Linux and Shell Basics Every DevOps Engineer Needs <span class=\"soon\">Coming soon<\/span><\/li>\n<li>Git for Teams: Branches, Pull Requests and Trunk-Based Development <span class=\"soon\">Coming soon<\/span><\/li>\n<li>Automated Testing for Pipelines: Unit, Integration and End-to-End <span class=\"soon\">Coming soon<\/span><\/li>\n<li>Your First CI Pipeline with GitHub Actions <span class=\"soon\">Coming soon<\/span><\/li>\n<li>Docker Basics: Images, Containers and Dockerfiles <span class=\"soon\">Coming soon<\/span><\/li>\n<li>Writing Small, Secure, Production-Ready Dockerfiles <span class=\"soon\">Coming soon<\/span><\/li>\n<li>Container Registries and Image Versioning <span class=\"soon\">Coming soon<\/span><\/li>\n<li>Build Artifacts, Versioning and Semantic Releases <span class=\"soon\">Coming soon<\/span><\/li>\n<li>Continuous Delivery vs Continuous Deployment: Your First Release Pipeline <span class=\"soon\">Coming soon<\/span><\/li>\n<\/ol>\n<h4>Intermediate<\/h4>\n<ol start=\"11\">\n<li>Environments, Configuration and Secrets Management <span class=\"soon\">Coming soon<\/span><\/li>\n<li>GitHub Actions Deep Dive: Matrix Builds, Caching and Reusable Workflows <span class=\"soon\">Coming soon<\/span><\/li>\n<li>GitLab CI\/CD and Jenkins: How Other CI Tools Work <span class=\"soon\">Coming soon<\/span><\/li>\n<li>Infrastructure as Code with Terraform <span class=\"soon\">Coming soon<\/span><\/li>\n<li>Configuration Management with Ansible <span class=\"soon\">Coming soon<\/span><\/li>\n<li>Kubernetes Essentials for CI\/CD <span class=\"soon\">Coming soon<\/span><\/li>\n<li>Packaging Apps for Kubernetes with Helm and Kustomize <span class=\"soon\">Coming soon<\/span><\/li>\n<li>GitOps with Argo CD <span class=\"soon\">Coming soon<\/span><\/li>\n<li>Deployment Strategies: Rolling, Blue-Green and Canary <span class=\"soon\">Coming soon<\/span><\/li>\n<li>Feature Flags and Progressive Delivery <span class=\"soon\">Coming soon<\/span><\/li>\n<\/ol>\n<h4>Advanced<\/h4>\n<ol start=\"21\">\n<li>DevSecOps: Code, Dependency and Container Scanning in CI <span class=\"soon\">Coming soon<\/span><\/li>\n<li>Software Supply Chain Security: SBOMs, Signing and SLSA <span class=\"soon\">Coming soon<\/span><\/li>\n<li>Observability: Metrics, Logs and Traces with Prometheus, Grafana and OpenTelemetry <span class=\"soon\">Coming soon<\/span><\/li>\n<li>Alerts, SLOs and Incident Response <span class=\"soon\">Coming soon<\/span><\/li>\n<li>Fast CI for Monorepos: Affected Builds and Remote Caching <span class=\"soon\">Coming soon<\/span><\/li>\n<li>Self-Hosted Runners and Scaling CI Cost-Effectively <span class=\"soon\">Coming soon<\/span><\/li>\n<li>Platform Engineering and Internal Developer Platforms <span class=\"soon\">Coming soon<\/span><\/li>\n<li>AI in DevOps: AI Code Review and Agentic Pipelines <span class=\"soon\">Coming soon<\/span><\/li>\n<li>Measuring DevOps with DORA Metrics <span class=\"soon\">Coming soon<\/span><\/li>\n<li>Final Project: A Complete Pipeline from Commit to Production <span class=\"soon\">Coming soon<\/span><\/li>\n<\/ol>\n<\/details>\n\n<nav class=\"dd-toc\" aria-label=\"Table of contents\">\n<strong>In this part<\/strong>\n<ol>\n<li><a href=\"#what-is-devops\">What is DevOps?<\/a><\/li>\n<li><a href=\"#why-devops\">The problem DevOps solves<\/a><\/li>\n<li><a href=\"#devops-lifecycle\">The DevOps lifecycle<\/a><\/li>\n<li><a href=\"#what-is-ci-cd\">What is CI\/CD?<\/a><\/li>\n<li><a href=\"#pipeline-anatomy\">Anatomy of a pipeline<\/a><\/li>\n<li><a href=\"#hands-on-app\">Hands-on: an app with tests<\/a><\/li>\n<li><a href=\"#local-pipeline\">Your first pipeline (shell script)<\/a><\/li>\n<li><a href=\"#github-actions\">The same pipeline on GitHub Actions<\/a><\/li>\n<li><a href=\"#tools\">DevOps tools map<\/a><\/li>\n<li><a href=\"#dora-metrics\">Measuring DevOps: DORA metrics<\/a><\/li>\n<li><a href=\"#common-errors\">Common errors and fixes<\/a><\/li>\n<li><a href=\"#best-practices\">Best practices<\/a><\/li>\n<li><a href=\"#practice\">Practice task<\/a><\/li>\n<li><a href=\"#faq\">FAQ<\/a><\/li>\n<\/ol>\n<\/nav>\n<\/div>\n\n\n\n<div class=\"dd-post\">\n<h2 id=\"what-is-devops\">What is DevOps? (simple definition)<\/h2>\n<p><strong>DevOps<\/strong> is a combination of two words: <strong>Development<\/strong> (the people who write the code) and <strong>Operations<\/strong> (the people who run that code on servers and keep it healthy). DevOps is a <strong>culture and a set of practices<\/strong> where these two groups work as <em>one team<\/em>, share responsibility for the product, and <strong>automate<\/strong> as much of the work as possible, from testing to deployment to monitoring.<\/p>\n<p>A simple way to remember it:<\/p>\n<div class=\"dd-note\"><strong>DevOps = people + process + automation.<\/strong> The goal is to ship small changes to users <em>quickly<\/em> and <em>safely<\/em>, again and again, and to learn from what happens in production.<\/div>\n<p>DevOps is <strong>not<\/strong> a single tool, a programming language or only a job title. You cannot install DevOps. Tools like GitHub Actions, Docker, Kubernetes and Terraform <em>support<\/em> DevOps, but the real change is in how the team works: small batches, fast feedback and shared ownership. Many people summarise the culture with the word <strong>CALMS<\/strong>: Culture, Automation, Lean (small batches, less waste), Measurement and Sharing.<\/p>\n\n<h2 id=\"why-devops\">The problem DevOps solves<\/h2>\n<p>Imagine a typical company before DevOps. Developers spend three months building features. When they are \u201cdone\u201d, they hand a big package of code to the operations team with a document of setup steps. Operations try to install it on production servers on a Saturday night. Something breaks. Developers say <em>\u201cit works on my machine\u201d<\/em>, operations say <em>\u201cyour code is broken\u201d<\/em>, and users wait.<\/p>\n<p>The two teams also have opposite goals: developers are rewarded for <strong>change<\/strong> (new features), and operations are rewarded for <strong>stability<\/strong> (no outages). This gap is often called the <strong>wall of confusion<\/strong>.<\/p>\n<figure>\n<svg viewBox=\"0 0 1000 400\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" role=\"img\" aria-label=\"Before DevOps, developers throw code over a wall to operations. With DevOps, one team shares an automated pipeline from commit to production.\">\n<rect width=\"1000\" height=\"400\" rx=\"14\" fill=\"#0b1020\"\/>\n<line x1=\"500\" y1=\"20\" x2=\"500\" y2=\"380\" stroke=\"#2a3366\" stroke-width=\"2\" stroke-dasharray=\"6 6\"\/>\n<text x=\"250\" y=\"44\" text-anchor=\"middle\" font-family=\"Segoe UI,Arial,sans-serif\" font-size=\"22\" font-weight=\"800\" fill=\"#ff8a8a\">\u274c Before DevOps<\/text>\n<text x=\"750\" y=\"44\" text-anchor=\"middle\" font-family=\"Segoe UI,Arial,sans-serif\" font-size=\"22\" font-weight=\"800\" fill=\"#7ee2a8\">\u2705 With DevOps<\/text>\n<rect x=\"40\" y=\"150\" width=\"140\" height=\"80\" rx=\"14\" fill=\"#1b2250\" stroke=\"#3178c6\" stroke-width=\"2\"\/>\n<text x=\"110\" y=\"185\" text-anchor=\"middle\" font-family=\"Segoe UI,Arial,sans-serif\" font-size=\"20\" font-weight=\"700\" fill=\"#fff\">\ud83d\udc69\u200d\ud83d\udcbb Dev<\/text>\n<text x=\"110\" y=\"210\" text-anchor=\"middle\" font-family=\"Segoe UI,Arial,sans-serif\" font-size=\"14\" fill=\"#aab4e8\">&#8220;ship new features!&#8221;<\/text>\n<g fill=\"#7a4b3a\" stroke=\"#0b1020\" stroke-width=\"2\">\n<rect x=\"232\" y=\"110\" width=\"36\" height=\"24\"\/><rect x=\"232\" y=\"134\" width=\"36\" height=\"24\"\/><rect x=\"232\" y=\"158\" width=\"36\" height=\"24\"\/><rect x=\"232\" y=\"182\" width=\"36\" height=\"24\"\/><rect x=\"232\" y=\"206\" width=\"36\" height=\"24\"\/><rect x=\"232\" y=\"230\" width=\"36\" height=\"24\"\/><rect x=\"232\" y=\"254\" width=\"36\" height=\"24\"\/>\n<\/g>\n<text x=\"250\" y=\"300\" text-anchor=\"middle\" font-family=\"Segoe UI,Arial,sans-serif\" font-size=\"14\" fill=\"#ffb4b4\">wall of confusion<\/text>\n<rect x=\"320\" y=\"150\" width=\"140\" height=\"80\" rx=\"14\" fill=\"#1b2250\" stroke=\"#7c5cff\" stroke-width=\"2\"\/>\n<text x=\"390\" y=\"185\" text-anchor=\"middle\" font-family=\"Segoe UI,Arial,sans-serif\" font-size=\"20\" font-weight=\"700\" fill=\"#fff\">\ud83e\uddd1\u200d\ud83d\udd27 Ops<\/text>\n<text x=\"390\" y=\"210\" text-anchor=\"middle\" font-family=\"Segoe UI,Arial,sans-serif\" font-size=\"14\" fill=\"#aab4e8\">&#8220;keep it stable!&#8221;<\/text>\n<path id=\"ddthrow\" d=\"M150 140 Q 250 40 360 140\" fill=\"none\" stroke=\"#ff8a8a\" stroke-width=\"2\" stroke-dasharray=\"6 6\"\/>\n<text font-family=\"Segoe UI,Arial,sans-serif\" font-size=\"22\"><textPath href=\"#ddthrow\" startOffset=\"0\">\ud83d\udce6<\/textPath><\/text>\n<circle r=\"7\" fill=\"#ff8a8a\"><animateMotion dur=\"2.6s\" repeatCount=\"indefinite\"><mpath href=\"#ddthrow\"\/><\/animateMotion><\/circle>\n<text x=\"250\" y=\"340\" text-anchor=\"middle\" font-family=\"Segoe UI,Arial,sans-serif\" font-size=\"15\" fill=\"#c9d1ff\">Manual handover \u00b7 releases every few months<\/text>\n<text x=\"250\" y=\"364\" text-anchor=\"middle\" font-family=\"Segoe UI,Arial,sans-serif\" font-size=\"15\" fill=\"#c9d1ff\">&#8220;It works on my machine!&#8221; \u00b7 blame games<\/text>\n<rect x=\"560\" y=\"90\" width=\"380\" height=\"64\" rx=\"14\" fill=\"url(#ddac)\"\/>\n<text x=\"750\" y=\"130\" text-anchor=\"middle\" font-family=\"Segoe UI,Arial,sans-serif\" font-size=\"20\" font-weight=\"800\" fill=\"#fff\">\ud83d\udc69\u200d\ud83d\udcbb + \ud83e\uddd1\u200d\ud83d\udd27 One team, shared goals<\/text>\n<path d=\"M750 154 V185\" stroke=\"#7c5cff\" stroke-width=\"3\"\/>\n<rect x=\"560\" y=\"186\" width=\"380\" height=\"96\" rx=\"14\" fill=\"#151b3b\" stroke=\"#7c5cff\" stroke-width=\"2\"\/>\n<text x=\"750\" y=\"214\" text-anchor=\"middle\" font-family=\"Segoe UI,Arial,sans-serif\" font-size=\"16\" font-weight=\"700\" fill=\"#c9d1ff\">Automated CI\/CD pipeline<\/text>\n<path id=\"ddshared\" d=\"M590 248 H910\" stroke=\"#3178c6\" stroke-width=\"3\" stroke-dasharray=\"7 7\"\/>\n<text x=\"600\" y=\"270\" font-family=\"Segoe UI,Arial,sans-serif\" font-size=\"14\" fill=\"#aab4e8\">commit<\/text><text x=\"690\" y=\"270\" font-family=\"Segoe UI,Arial,sans-serif\" font-size=\"14\" fill=\"#aab4e8\">build<\/text><text x=\"760\" y=\"270\" font-family=\"Segoe UI,Arial,sans-serif\" font-size=\"14\" fill=\"#aab4e8\">test<\/text><text x=\"840\" y=\"270\" font-family=\"Segoe UI,Arial,sans-serif\" font-size=\"14\" fill=\"#aab4e8\">deploy<\/text>\n<circle r=\"7\" fill=\"#7ee2a8\"><animateMotion dur=\"2.4s\" repeatCount=\"indefinite\"><mpath href=\"#ddshared\"\/><\/animateMotion><\/circle>\n<text x=\"750\" y=\"340\" text-anchor=\"middle\" font-family=\"Segoe UI,Arial,sans-serif\" font-size=\"15\" fill=\"#c9d1ff\">Small changes \u00b7 many releases a day<\/text>\n<text x=\"750\" y=\"364\" text-anchor=\"middle\" font-family=\"Segoe UI,Arial,sans-serif\" font-size=\"15\" fill=\"#c9d1ff\">Fast feedback \u00b7 shared ownership<\/text>\n<\/svg>\n<figcaption>Figure 1: DevOps removes the \u201cwall\u201d between developers and operations and replaces manual handovers with one shared, automated pipeline.<\/figcaption>\n<\/figure>\n<p>DevOps fixes this with a few simple ideas:<\/p>\n<div class=\"dd-cards\">\n<div class=\"dd-card\"><b>Small, frequent changes<\/b>A 20-line change is easy to test, review and roll back. A 20,000-line release is not.<\/div>\n<div class=\"dd-card\"><b>Automate the boring parts<\/b>Builds, tests, security checks and deployments run the same way every time, without someone typing commands by hand.<\/div>\n<div class=\"dd-card\"><b>Fast feedback<\/b>If you break something, a pipeline tells you in minutes, not weeks later from an angry customer.<\/div>\n<div class=\"dd-card\"><b>Shared ownership<\/b>\u201cYou build it, you run it.\u201d The team that writes the code also watches how it behaves in production.<\/div>\n<\/div>\n\n<h2 id=\"devops-lifecycle\">The DevOps lifecycle (the infinity loop)<\/h2>\n<p>You will often see DevOps drawn as an infinity loop, like in the banner at the top. The left side is <strong>Dev<\/strong> and the right side is <strong>Ops<\/strong>. Work flows around the loop forever, because software is never \u201cfinished\u201d:<\/p>\n<div class=\"dd-tablewrap\"><table>\n<thead><tr><th>Stage<\/th><th>What happens<\/th><th>Example tools<\/th><\/tr><\/thead>\n<tbody>\n<tr><td><strong>1. Plan<\/strong><\/td><td>Decide what to build next and split it into small tasks.<\/td><td>Jira, GitHub Issues, Linear<\/td><\/tr>\n<tr><td><strong>2. Code<\/strong><\/td><td>Write code in short-lived branches and open pull requests.<\/td><td>Git, GitHub, GitLab, VS Code<\/td><\/tr>\n<tr><td><strong>3. Build<\/strong><\/td><td>Install dependencies and compile or bundle the app.<\/td><td>npm, Maven, Gradle, Docker<\/td><\/tr>\n<tr><td><strong>4. Test<\/strong><\/td><td>Run automatic checks: linting, unit tests, integration tests, security scans.<\/td><td>Jest, node:test, pytest, Playwright<\/td><\/tr>\n<tr><td><strong>5. Release<\/strong><\/td><td>Package a versioned artifact that is ready to deploy.<\/td><td>GitHub Releases, container registries<\/td><\/tr>\n<tr><td><strong>6. Deploy<\/strong><\/td><td>Put the release on servers, safely and repeatably.<\/td><td>GitHub Actions, Argo CD, Kubernetes<\/td><\/tr>\n<tr><td><strong>7. Operate<\/strong><\/td><td>Run and scale the infrastructure, manage configuration.<\/td><td>Terraform, Ansible, cloud consoles<\/td><\/tr>\n<tr><td><strong>8. Monitor<\/strong><\/td><td>Watch errors, speed and usage, and feed what you learn back into \u201cPlan\u201d.<\/td><td>Prometheus, Grafana, OpenTelemetry<\/td><\/tr>\n<\/tbody><\/table><\/div>\n<p>Do not worry about the tool names yet. This series covers each stage one by one, in that order.<\/p>\n\n<h2 id=\"what-is-ci-cd\">What is CI\/CD?<\/h2>\n<p><strong>CI\/CD<\/strong> is the heart of DevOps automation. It is the \u201cconveyor belt\u201d that carries your code from the <em>Code<\/em> stage to the <em>Deploy<\/em> stage of the loop. The letters stand for three related practices. Click the tabs below to compare them:<\/p>\n<div class=\"dd-tabs\" role=\"group\" aria-label=\"Compare CI, continuous delivery, continuous deployment and DevOps\">\n<input type=\"radio\" name=\"ddcd\" id=\"ti1\" checked>\n<input type=\"radio\" name=\"ddcd\" id=\"ti2\">\n<input type=\"radio\" name=\"ddcd\" id=\"ti3\">\n<input type=\"radio\" name=\"ddcd\" id=\"ti4\">\n<div class=\"labels\"><label for=\"ti1\">Continuous Integration<\/label><label for=\"ti2\">Continuous Delivery<\/label><label for=\"ti3\">Continuous Deployment<\/label><label for=\"ti4\">DevOps<\/label><\/div>\n<div class=\"panel p1\"><p><strong>Continuous Integration (CI)<\/strong> means every developer merges small changes into the main branch often (at least daily), and <strong>every merge is automatically built and tested<\/strong>.<\/p><ul><li><strong>Goal:<\/strong> find bugs within minutes, while the change is still fresh in your head.<\/li><li><strong>Ends with:<\/strong> a green (pass) or red (fail) result, and often a build artifact.<\/li><li><strong>Example:<\/strong> you open a pull request \u2192 GitHub Actions runs lint + tests \u2192 the PR shows a green tick.<\/li><\/ul><\/div>\n<div class=\"panel p2\"><p><strong>Continuous Delivery<\/strong> goes one step further: every change that passes CI is <strong>automatically prepared for release<\/strong> and deployed to a test (staging) environment.<\/p><ul><li><strong>Goal:<\/strong> the main branch is <em>always<\/em> ready to release.<\/li><li><strong>Production release:<\/strong> a human clicks \u201capprove\u201d (a <em>manual gate<\/em>).<\/li><li><strong>Good for:<\/strong> banks, apps that go through store reviews, or teams that want a final check.<\/li><\/ul><\/div>\n<div class=\"panel p3\"><p><strong>Continuous Deployment<\/strong> removes the manual gate: every change that passes all automated checks goes <strong>straight to production<\/strong>, with no human click.<\/p><ul><li><strong>Goal:<\/strong> users get fixes and features within minutes.<\/li><li><strong>Needs:<\/strong> very good automated tests, monitoring and an easy rollback.<\/li><li><strong>Good for:<\/strong> web apps and SaaS products that release many times a day.<\/li><\/ul><\/div>\n<div class=\"panel p4\"><p><strong>DevOps<\/strong> is the bigger picture: a <strong>culture and set of practices<\/strong> where development and operations work as one team and automate the path from idea to production.<\/p><ul><li><strong>CI\/CD is a core practice<\/strong> of DevOps, but DevOps also includes infrastructure as code, monitoring, incident response and shared ownership.<\/li><li><strong>Remember:<\/strong> you can buy CI\/CD tools, but you cannot buy DevOps. It is how a team works.<\/li><\/ul><\/div>\n<\/div>\n<p>A quick way to remember the difference between the two \u201cCDs\u201d: in <strong>continuous delivery<\/strong> the release button exists and a person presses it; in <strong>continuous deployment<\/strong> the pipeline presses it for you. Most teams start with CI, then add continuous delivery, and only move to continuous deployment once their tests and monitoring are strong.<\/p>\n\n<h2 id=\"pipeline-anatomy\">Anatomy of a CI\/CD pipeline<\/h2>\n<p>A <strong>pipeline<\/strong> is a set of automated stages that run, in order, every time something changes in your repository. Each stage must pass before the next one starts. That \u201cstop the line\u201d rule is what makes pipelines so useful: broken code never reaches users.<\/p>\n<figure>\n<svg viewBox=\"0 0 1000 380\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" role=\"img\" aria-label=\"Anatomy of a CI\/CD pipeline: a git push triggers build, test, package, deploy to staging, an approval gate and deploy to production. A failure sends feedback to the developer.\">\n<rect width=\"1000\" height=\"380\" rx=\"14\" fill=\"#0b1020\"\/>\n<text x=\"30\" y=\"44\" font-family=\"Segoe UI,Arial,sans-serif\" font-size=\"20\" font-weight=\"800\" fill=\"#fff\">Anatomy of a CI\/CD pipeline<\/text>\n<rect x=\"30\" y=\"74\" width=\"420\" height=\"26\" rx=\"8\" fill=\"#3178c6\" opacity=\".25\"\/><text x=\"240\" y=\"92\" text-anchor=\"middle\" font-family=\"Segoe UI,Arial,sans-serif\" font-size=\"14\" font-weight=\"700\" fill=\"#9cc3ff\">CONTINUOUS INTEGRATION (CI)<\/text>\n<rect x=\"470\" y=\"74\" width=\"500\" height=\"26\" rx=\"8\" fill=\"#7c5cff\" opacity=\".25\"\/><text x=\"720\" y=\"92\" text-anchor=\"middle\" font-family=\"Segoe UI,Arial,sans-serif\" font-size=\"14\" font-weight=\"700\" fill=\"#c4b5ff\">CONTINUOUS DELIVERY \/ DEPLOYMENT (CD)<\/text>\n<path id=\"ddflow\" d=\"M60 110 H950\" stroke=\"url(#ddac)\" stroke-width=\"3\" fill=\"none\" stroke-dasharray=\"8 8\"\/>\n<g><rect x=\"30\" y=\"120\" width=\"90\" height=\"70\" rx=\"12\" fill=\"url(#ddac)\"\/><text x=\"75\" y=\"151\" text-anchor=\"middle\" font-family=\"Segoe UI,Arial,sans-serif\" font-size=\"16\" font-weight=\"800\" fill=\"#fff\">Trigger<\/text><text x=\"75\" y=\"172\" text-anchor=\"middle\" font-family=\"Segoe UI,Arial,sans-serif\" font-size=\"12.5\" fill=\"#eef\">git push \/ PR<\/text><\/g>\n<g><rect x=\"135\" y=\"120\" width=\"118\" height=\"70\" rx=\"12\" fill=\"#1b2250\" stroke=\"#3178c6\" stroke-width=\"2\"\/><text x=\"194\" y=\"151\" text-anchor=\"middle\" font-family=\"Segoe UI,Arial,sans-serif\" font-size=\"16\" font-weight=\"700\" fill=\"#fff\">\ud83d\udd28 Build<\/text><text x=\"194\" y=\"172\" text-anchor=\"middle\" font-family=\"Segoe UI,Arial,sans-serif\" font-size=\"12.5\" fill=\"#aab4e8\">install + compile<\/text><\/g>\n<g><rect x=\"263\" y=\"120\" width=\"118\" height=\"70\" rx=\"12\" fill=\"#1b2250\" stroke=\"#3178c6\" stroke-width=\"2\"\/><text x=\"322\" y=\"151\" text-anchor=\"middle\" font-family=\"Segoe UI,Arial,sans-serif\" font-size=\"16\" font-weight=\"700\" fill=\"#fff\">\u2705 Test<\/text><text x=\"322\" y=\"172\" text-anchor=\"middle\" font-family=\"Segoe UI,Arial,sans-serif\" font-size=\"12.5\" fill=\"#aab4e8\">lint + unit tests<\/text><\/g>\n<g><rect x=\"391\" y=\"120\" width=\"118\" height=\"70\" rx=\"12\" fill=\"#1b2250\" stroke=\"#7c5cff\" stroke-width=\"2\"\/><text x=\"450\" y=\"151\" text-anchor=\"middle\" font-family=\"Segoe UI,Arial,sans-serif\" font-size=\"16\" font-weight=\"700\" fill=\"#fff\">\ud83d\udce6 Package<\/text><text x=\"450\" y=\"172\" text-anchor=\"middle\" font-family=\"Segoe UI,Arial,sans-serif\" font-size=\"12.5\" fill=\"#aab4e8\">artifact \/ image<\/text><\/g>\n<g><rect x=\"519\" y=\"120\" width=\"118\" height=\"70\" rx=\"12\" fill=\"#1b2250\" stroke=\"#7c5cff\" stroke-width=\"2\"\/><text x=\"578\" y=\"151\" text-anchor=\"middle\" font-family=\"Segoe UI,Arial,sans-serif\" font-size=\"16\" font-weight=\"700\" fill=\"#fff\">\ud83e\uddea Staging<\/text><text x=\"578\" y=\"172\" text-anchor=\"middle\" font-family=\"Segoe UI,Arial,sans-serif\" font-size=\"12.5\" fill=\"#aab4e8\">deploy + checks<\/text><\/g>\n<g><rect x=\"647\" y=\"120\" width=\"96\" height=\"70\" rx=\"12\" fill=\"#2a1f55\" stroke=\"#febc2e\" stroke-width=\"2\"\/><text x=\"695\" y=\"151\" text-anchor=\"middle\" font-family=\"Segoe UI,Arial,sans-serif\" font-size=\"16\" font-weight=\"700\" fill=\"#fff\">\u270b Gate<\/text><text x=\"695\" y=\"172\" text-anchor=\"middle\" font-family=\"Segoe UI,Arial,sans-serif\" font-size=\"12.5\" fill=\"#ffe3a3\">approval<\/text><\/g>\n<g><rect x=\"758\" y=\"120\" width=\"212\" height=\"70\" rx=\"12\" fill=\"#13361f\" stroke=\"#28c840\" stroke-width=\"2\"\/><text x=\"864\" y=\"151\" text-anchor=\"middle\" font-family=\"Segoe UI,Arial,sans-serif\" font-size=\"16\" font-weight=\"700\" fill=\"#fff\">\ud83d\ude80 Production<\/text><text x=\"864\" y=\"172\" text-anchor=\"middle\" font-family=\"Segoe UI,Arial,sans-serif\" font-size=\"12.5\" fill=\"#b6f5c4\">real users<\/text><\/g>\n<circle r=\"7\" fill=\"#ffffff\"><animateMotion dur=\"5s\" repeatCount=\"indefinite\"><mpath href=\"#ddflow\"\/><\/animateMotion><\/circle>\n<path d=\"M322 192 C 322 270, 75 270, 75 194\" fill=\"none\" stroke=\"#ff6b6b\" stroke-width=\"2.5\" stroke-dasharray=\"6 6\"\/>\n<path d=\"M69 204 L75 192 L81 204\" fill=\"none\" stroke=\"#ff6b6b\" stroke-width=\"2.5\"\/>\n<text x=\"200\" y=\"285\" text-anchor=\"middle\" font-family=\"Segoe UI,Arial,sans-serif\" font-size=\"14\" fill=\"#ffb4b4\">\u274c test fails \u2192 pipeline stops \u2192 developer is told in minutes<\/text>\n<text x=\"30\" y=\"330\" font-family=\"Segoe UI,Arial,sans-serif\" font-size=\"14.5\" xml:space=\"preserve\" fill=\"#c9d1ff\"><tspan font-weight=\"700\" fill=\"#fff\">Stage<\/tspan> = a phase (build, test\u2026)  \u00b7  <tspan font-weight=\"700\" fill=\"#fff\">Job<\/tspan> = work on one machine  \u00b7  <tspan font-weight=\"700\" fill=\"#fff\">Step<\/tspan> = one command<\/text>\n<text x=\"30\" y=\"356\" font-family=\"Segoe UI,Arial,sans-serif\" font-size=\"14.5\" fill=\"#c9d1ff\"><tspan font-weight=\"700\" fill=\"#fff\">Artifact<\/tspan> = the built output (zip, Docker image) that moves from stage to stage<\/text>\n<\/svg>\n<figcaption>Figure 2: A typical pipeline. CI covers build and test; CD takes the same tested artifact through staging to production. A failure anywhere stops the line.<\/figcaption>\n<\/figure>\n<p>Here are the words you will see in every CI\/CD tool:<\/p>\n<ul>\n<li><strong>Trigger:<\/strong> the event that starts the pipeline, such as a push, a pull request, a schedule or a manual button.<\/li>\n<li><strong>Runner (or agent):<\/strong> the machine that runs the work. In GitHub Actions it is a fresh virtual machine for each job.<\/li>\n<li><strong>Stage \/ Job \/ Step:<\/strong> a stage is a phase (build, test), a job is a group of steps that runs on one runner, and a step is a single command or action.<\/li>\n<li><strong>Artifact:<\/strong> the output of the build (a zip, a <code>dist\/<\/code> folder, a Docker image). The <em>same<\/em> artifact is tested and then deployed, so what you tested is exactly what goes live.<\/li>\n<li><strong>Environment:<\/strong> where the app is deployed, such as <em>staging<\/em> (for testing) and <em>production<\/em> (for real users).<\/li>\n<li><strong>Gate:<\/strong> a check that must pass before moving on, like an approval or a minimum test coverage.<\/li>\n<\/ul>\n<\/div>\n\n\n\n<div class=\"dd-post\">\n<h2 id=\"hands-on-app\">Hands-on: a small app with tests<\/h2>\n<p>A pipeline is only as good as the checks it runs, so let us start with a tiny piece of \u201cbusiness logic\u201d: a function that calculates a shopping cart total with 18% GST. We will write it in Node.js and add three automated tests using the built-in <code>node:test<\/code> runner (no extra libraries needed).<\/p>\n<div class=\"dd-vsc dd-vsc-termonly\" role=\"group\" aria-label=\"Terminal: devops-part1 \u2014 bash\">\n<div class=\"dd-vsc-bar\"><span class=\"dd-dots\"><i><\/i><i><\/i><i><\/i><\/span><span class=\"dd-vsc-title\">devops-part1 \u2014 bash<\/span><\/div>\n<pre class=\"dd-vsc-code\"><code><span class=\"l\"><span class=\"c\"># 1. Create the project (needs Node.js 22+ and Git)<\/span><\/span>\n<span class=\"l\"><span class=\"gp\">$<\/span> mkdir devops-part1 &amp;&amp; cd devops-part1<\/span>\n<span class=\"l\"><span class=\"gp\">$<\/span> mkdir src test<\/span>\n<span class=\"l\"><span class=\"gp\">$<\/span> git init<\/span>\n<span class=\"l\"><\/span>\n<span class=\"l\"><span class=\"c\"># 2. Create package.json (copy it from the editor above), then<\/span><\/span>\n<span class=\"l\"><span class=\"c\">#    generate package-lock.json so \"npm ci\" works in the pipeline<\/span><\/span>\n<span class=\"l\"><span class=\"gp\">$<\/span> npm install<\/span>\n<span class=\"l\"><\/span>\n<span class=\"l\"><span class=\"c\"># 3. Run the tests by hand once<\/span><\/span>\n<span class=\"l\"><span class=\"gp\">$<\/span> npm test<\/span><\/code><\/pre>\n<\/div>\n<div class=\"dd-vsc\" role=\"group\" aria-label=\"Code editor: price.js, price.test.js, package.json\">\n<input type=\"radio\" name=\"v1\" id=\"v1f1\" class=\"f1\" checked>\n<input type=\"radio\" name=\"v1\" id=\"v1f2\" class=\"f2\">\n<input type=\"radio\" name=\"v1\" id=\"v1f3\" class=\"f3\">\n<input type=\"checkbox\" id=\"v1r2\" class=\"r2\">\n<div class=\"dd-vsc-bar\"><span class=\"dd-dots\"><i><\/i><i><\/i><i><\/i><\/span><span class=\"dd-vsc-title\">3 files \u2014 devops-part1 \u2014 Visual Studio Code<\/span><\/div>\n<div class=\"dd-vsc-tabs\">\n<label for=\"v1f1\" class=\"t1\"><b class=\"ic js\">JS<\/b>price.js<\/label>\n<label for=\"v1f2\" class=\"t2\"><b class=\"ic js\">JS<\/b>price.test.js<\/label>\n<label for=\"v1f3\" class=\"t3\"><b class=\"ic js\">{ }<\/b>package.json<\/label>\n<label for=\"v1r2\" class=\"run run2\" title=\"Show the output in the terminal\">\u25b6 Run<\/label>\n<\/div>\n<div class=\"dd-vsc-pane p1\">\n<div class=\"dd-vsc-crumbs\">devops-part1 \u203a src \u203a price.js<\/div>\n<pre class=\"dd-vsc-code\"><code><span class=\"l\"><span class=\"c\">\/\/ A tiny piece of \"business logic\" our pipeline will check on every push.<\/span><\/span>\n<span class=\"l\"><span class=\"k\">export<\/span> <span class=\"k\">const<\/span> <span class=\"n\">GST_RATE<\/span> = <span class=\"m\">0.18<\/span>; <span class=\"c\">\/\/ 18% GST<\/span><\/span>\n<span class=\"l\"><\/span>\n<span class=\"l\"><span class=\"k\">export<\/span> <span class=\"k\">function<\/span> <span class=\"n\">totalWithGst<\/span>(<span class=\"n\">items<\/span>) {<\/span>\n<span class=\"l\">  <span class=\"k\">if<\/span> (!<span class=\"nb\">Array<\/span>.<span class=\"n\">isArray<\/span>(<span class=\"n\">items<\/span>)) {<\/span>\n<span class=\"l\">    <span class=\"k\">throw<\/span> new TypeError(<span class=\"s\">\"items must be an array\"<\/span>);<\/span>\n<span class=\"l\">  }<\/span>\n<span class=\"l\">  <span class=\"k\">const<\/span> <span class=\"n\">subtotal<\/span> = <span class=\"n\">items<\/span>.<span class=\"n\">reduce<\/span>((<span class=\"n\">sum<\/span>, <span class=\"n\">item<\/span>) =&gt; <span class=\"n\">sum<\/span> + <span class=\"n\">item<\/span>.<span class=\"n\">price<\/span> * <span class=\"n\">item<\/span>.<span class=\"n\">qty<\/span>, <span class=\"m\">0<\/span>);<\/span>\n<span class=\"l\">  <span class=\"k\">const<\/span> <span class=\"n\">total<\/span> = <span class=\"n\">subtotal<\/span> * (<span class=\"m\">1<\/span> + <span class=\"n\">GST_RATE<\/span>);<\/span>\n<span class=\"l\">  <span class=\"k\">return<\/span> <span class=\"nb\">Math<\/span>.<span class=\"n\">round<\/span>(<span class=\"n\">total<\/span> * <span class=\"m\">100<\/span>) \/ <span class=\"m\">100<\/span>; <span class=\"c\">\/\/ round to 2 decimals (paise)<\/span><\/span>\n<span class=\"l\">}<\/span><\/code><\/pre>\n<div class=\"dd-vsc-status\"><span>\u2387 main<\/span><span>Ln 11, Col 1<\/span><span class=\"sp\"><\/span><span>Spaces: 2<\/span><span>UTF-8<\/span><span>LF<\/span><span>JavaScript<\/span><\/div>\n<\/div>\n<div class=\"dd-vsc-pane p2\">\n<div class=\"dd-vsc-crumbs\">devops-part1 \u203a test \u203a price.test.js<\/div>\n<pre class=\"dd-vsc-code\"><code><span class=\"l\"><span class=\"k\">import<\/span> { <span class=\"n\">test<\/span> } <span class=\"k\">from<\/span> <span class=\"s\">\"node:test\"<\/span>;<\/span>\n<span class=\"l\"><span class=\"k\">import<\/span> <span class=\"n\">assert<\/span> <span class=\"k\">from<\/span> <span class=\"s\">\"node:assert\/strict\"<\/span>;<\/span>\n<span class=\"l\"><span class=\"k\">import<\/span> { <span class=\"n\">totalWithGst<\/span> } <span class=\"k\">from<\/span> <span class=\"s\">\"..\/src\/price.js\"<\/span>;<\/span>\n<span class=\"l\"><\/span>\n<span class=\"l\"><span class=\"n\">test<\/span>(<span class=\"s\">\"adds 18% GST to the cart total\"<\/span>, () =&gt; {<\/span>\n<span class=\"l\">  <span class=\"k\">const<\/span> <span class=\"n\">cart<\/span> = [{ <span class=\"n\">price<\/span>: <span class=\"m\">100<\/span>, <span class=\"n\">qty<\/span>: <span class=\"m\">2<\/span> }, { <span class=\"n\">price<\/span>: <span class=\"m\">50<\/span>, <span class=\"n\">qty<\/span>: <span class=\"m\">1<\/span> }];<\/span>\n<span class=\"l\">  <span class=\"n\">assert<\/span>.<span class=\"n\">equal<\/span>(<span class=\"n\">totalWithGst<\/span>(<span class=\"n\">cart<\/span>), <span class=\"m\">295<\/span>);<\/span>\n<span class=\"l\">});<\/span>\n<span class=\"l\"><\/span>\n<span class=\"l\"><span class=\"n\">test<\/span>(<span class=\"s\">\"an empty cart costs nothing\"<\/span>, () =&gt; {<\/span>\n<span class=\"l\">  <span class=\"n\">assert<\/span>.<span class=\"n\">equal<\/span>(<span class=\"n\">totalWithGst<\/span>([]), <span class=\"m\">0<\/span>);<\/span>\n<span class=\"l\">});<\/span>\n<span class=\"l\"><\/span>\n<span class=\"l\"><span class=\"n\">test<\/span>(<span class=\"s\">\"rejects bad input\"<\/span>, () =&gt; {<\/span>\n<span class=\"l\">  <span class=\"n\">assert<\/span>.<span class=\"k\">throws<\/span>(() =&gt; <span class=\"n\">totalWithGst<\/span>(<span class=\"s\">\"not a cart\"<\/span>), TypeError);<\/span>\n<span class=\"l\">});<\/span><\/code><\/pre>\n<div class=\"dd-vsc-term\"><div class=\"dd-term-head\"><span>TERMINAL<\/span><span>OUTPUT<\/span><span>PROBLEMS<\/span><span class=\"dd-term-note\">Real output (Node.js 22)<\/span><\/div><pre><code><span class=\"gp\">$<\/span> npm test\n\n&gt; devops-part1@1.0.0 test\n&gt; node --test --test-reporter=spec\n\n\u2714 adds 18% GST to the cart total (0.907775ms)\n\u2714 an empty cart costs nothing (0.133256ms)\n\u2714 rejects bad input (0.388574ms)\n\u2139 tests 3\n\u2139 suites 0\n\u2139 pass 3\n\u2139 fail 0\n\u2139 cancelled 0\n\u2139 skipped 0\n\u2139 todo 0\n\u2139 duration_ms 104.318471<\/code><\/pre><\/div>\n<div class=\"dd-vsc-status\"><span>\u2387 main<\/span><span>Ln 16, Col 1<\/span><span class=\"sp\"><\/span><span>Spaces: 2<\/span><span>UTF-8<\/span><span>LF<\/span><span>JavaScript<\/span><\/div>\n<\/div>\n<div class=\"dd-vsc-pane p3\">\n<div class=\"dd-vsc-crumbs\">devops-part1 \u203a package.json<\/div>\n<pre class=\"dd-vsc-code\"><code><span class=\"l\">{<\/span>\n<span class=\"l\">  <span class=\"kc\">\"name\"<\/span>: <span class=\"s\">\"devops-part1\"<\/span>,<\/span>\n<span class=\"l\">  <span class=\"kc\">\"version\"<\/span>: <span class=\"s\">\"1.0.0\"<\/span>,<\/span>\n<span class=\"l\">  <span class=\"kc\">\"type\"<\/span>: <span class=\"s\">\"module\"<\/span>,<\/span>\n<span class=\"l\">  <span class=\"kc\">\"scripts\"<\/span>: {<\/span>\n<span class=\"l\">    <span class=\"kc\">\"lint\"<\/span>: <span class=\"s\">\"node --check src\/price.js\"<\/span>,<\/span>\n<span class=\"l\">    <span class=\"kc\">\"test\"<\/span>: <span class=\"s\">\"node --test --test-reporter=spec\"<\/span>,<\/span>\n<span class=\"l\">    <span class=\"kc\">\"build\"<\/span>: <span class=\"s\">\"mkdir -p dist &amp;&amp; cp src\/*.js dist\/\"<\/span><\/span>\n<span class=\"l\">  }<\/span>\n<span class=\"l\">}<\/span><\/code><\/pre>\n<div class=\"dd-vsc-status\"><span>\u2387 main<\/span><span>Ln 10, Col 1<\/span><span class=\"sp\"><\/span><span>Spaces: 2<\/span><span>UTF-8<\/span><span>LF<\/span><span>JSON<\/span><\/div>\n<\/div>\n<\/div>\n<p class=\"dd-vsc-hint\">Click the tabs to switch files, then open <strong>price.test.js<\/strong> and press <strong>\u25b6 Run<\/strong> to see the test results.<\/p>\n<div class=\"dd-tip\"><strong>Why <code>package-lock.json<\/code> matters:<\/strong> pipelines use <code>npm ci<\/code> instead of <code>npm install<\/code>. It installs the <em>exact<\/em> versions from the lock file and fails if the lock file is missing or out of date. That is how CI avoids the classic \u201cbut it works on my machine\u201d problem.<\/div>\n<p>CI\/CD works the same way for any language. Here is the same logic and the same three tests in Python, using the built-in <code>unittest<\/code> module:<\/p>\n<div class=\"dd-vsc\" role=\"group\" aria-label=\"Code editor: price.py, test_price.py\">\n<input type=\"radio\" name=\"v2\" id=\"v2f1\" class=\"f1\" checked>\n<input type=\"radio\" name=\"v2\" id=\"v2f2\" class=\"f2\">\n<input type=\"checkbox\" id=\"v2r2\" class=\"r2\">\n<div class=\"dd-vsc-bar\"><span class=\"dd-dots\"><i><\/i><i><\/i><i><\/i><\/span><span class=\"dd-vsc-title\">2 files \u2014 devops-part1-py \u2014 Visual Studio Code<\/span><\/div>\n<div class=\"dd-vsc-tabs\">\n<label for=\"v2f1\" class=\"t1\"><b class=\"ic py\">PY<\/b>price.py<\/label>\n<label for=\"v2f2\" class=\"t2\"><b class=\"ic py\">PY<\/b>test_price.py<\/label>\n<label for=\"v2r2\" class=\"run run2\" title=\"Show the output in the terminal\">\u25b6 Run<\/label>\n<\/div>\n<div class=\"dd-vsc-pane p1\">\n<div class=\"dd-vsc-crumbs\">devops-part1-py \u203a price.py<\/div>\n<pre class=\"dd-vsc-code\"><code><span class=\"l\"><span class=\"c\"># The same business logic in Python - CI\/CD works for any language.<\/span><\/span>\n<span class=\"l\"><span class=\"n\">GST_RATE<\/span> = <span class=\"m\">0.18<\/span>  <span class=\"c\"># 18% GST<\/span><\/span>\n<span class=\"l\"><\/span>\n<span class=\"l\"><\/span>\n<span class=\"l\"><span class=\"k\">def<\/span> <span class=\"nf\">total_with_gst<\/span>(<span class=\"n\">items<\/span>):<\/span>\n<span class=\"l\">    <span class=\"k\">if<\/span> not <span class=\"nb\">isinstance<\/span>(<span class=\"n\">items<\/span>, <span class=\"nb\">list<\/span>):<\/span>\n<span class=\"l\">        <span class=\"k\">raise<\/span> TypeError(<span class=\"s\">\"items must be a list\"<\/span>)<\/span>\n<span class=\"l\">    <span class=\"n\">subtotal<\/span> = <span class=\"nb\">sum<\/span>(<span class=\"n\">item<\/span>[<span class=\"s\">\"price\"<\/span>] * <span class=\"n\">item<\/span>[<span class=\"s\">\"qty\"<\/span>] <span class=\"k\">for<\/span> <span class=\"n\">item<\/span> in <span class=\"n\">items<\/span>)<\/span>\n<span class=\"l\">    <span class=\"k\">return<\/span> <span class=\"nb\">round<\/span>(<span class=\"n\">subtotal<\/span> * (<span class=\"m\">1<\/span> + <span class=\"n\">GST_RATE<\/span>), <span class=\"m\">2<\/span>)<\/span><\/code><\/pre>\n<div class=\"dd-vsc-status\"><span>\u2387 main<\/span><span>Ln 9, Col 1<\/span><span class=\"sp\"><\/span><span>Spaces: 4<\/span><span>UTF-8<\/span><span>LF<\/span><span>Python<\/span><\/div>\n<\/div>\n<div class=\"dd-vsc-pane p2\">\n<div class=\"dd-vsc-crumbs\">devops-part1-py \u203a test_price.py<\/div>\n<pre class=\"dd-vsc-code\"><code><span class=\"l\"><span class=\"kn\">import<\/span> unittest<\/span>\n<span class=\"l\"><\/span>\n<span class=\"l\"><span class=\"kn\">from<\/span> price <span class=\"kn\">import<\/span> <span class=\"n\">total_with_gst<\/span><\/span>\n<span class=\"l\"><\/span>\n<span class=\"l\"><\/span>\n<span class=\"l\"><span class=\"k\">class<\/span> <span class=\"nc\">TestPrice<\/span>(<span class=\"n\">unittest<\/span>.<span class=\"n\">TestCase<\/span>):<\/span>\n<span class=\"l\">    <span class=\"k\">def<\/span> <span class=\"nf\">test_adds_gst<\/span>(<span class=\"nb\">self<\/span>):<\/span>\n<span class=\"l\">        <span class=\"n\">cart<\/span> = [{<span class=\"s\">\"price\"<\/span>: <span class=\"m\">100<\/span>, <span class=\"s\">\"qty\"<\/span>: <span class=\"m\">2<\/span>}, {<span class=\"s\">\"price\"<\/span>: <span class=\"m\">50<\/span>, <span class=\"s\">\"qty\"<\/span>: <span class=\"m\">1<\/span>}]<\/span>\n<span class=\"l\">        <span class=\"nb\">self<\/span>.<span class=\"n\">assertEqual<\/span>(<span class=\"n\">total_with_gst<\/span>(<span class=\"n\">cart<\/span>), <span class=\"m\">295.0<\/span>)<\/span>\n<span class=\"l\"><\/span>\n<span class=\"l\">    <span class=\"k\">def<\/span> <span class=\"nf\">test_empty_cart<\/span>(<span class=\"nb\">self<\/span>):<\/span>\n<span class=\"l\">        <span class=\"nb\">self<\/span>.<span class=\"n\">assertEqual<\/span>(<span class=\"n\">total_with_gst<\/span>([]), <span class=\"m\">0<\/span>)<\/span>\n<span class=\"l\"><\/span>\n<span class=\"l\">    <span class=\"k\">def<\/span> <span class=\"nf\">test_rejects_bad_input<\/span>(<span class=\"nb\">self<\/span>):<\/span>\n<span class=\"l\">        <span class=\"k\">with<\/span> <span class=\"nb\">self<\/span>.<span class=\"n\">assertRaises<\/span>(TypeError):<\/span>\n<span class=\"l\">            <span class=\"n\">total_with_gst<\/span>(<span class=\"s\">\"not a cart\"<\/span>)<\/span>\n<span class=\"l\"><\/span>\n<span class=\"l\"><\/span>\n<span class=\"l\"><span class=\"k\">if<\/span> <span class=\"n\">__name__<\/span> == <span class=\"s\">\"__main__\"<\/span>:<\/span>\n<span class=\"l\">    <span class=\"n\">unittest<\/span>.<span class=\"n\">main<\/span>()<\/span><\/code><\/pre>\n<div class=\"dd-vsc-term\"><div class=\"dd-term-head\"><span>TERMINAL<\/span><span>OUTPUT<\/span><span>PROBLEMS<\/span><span class=\"dd-term-note\">Real output (Python 3.13)<\/span><\/div><pre><code><span class=\"gp\">$<\/span> python -m unittest -v\ntest_adds_gst (test_price.TestPrice.test_adds_gst) ... ok\ntest_empty_cart (test_price.TestPrice.test_empty_cart) ... ok\ntest_rejects_bad_input (test_price.TestPrice.test_rejects_bad_input) ... ok\n\n----------------------------------------------------------------------\nRan 3 tests in 0.000s\n\nOK<\/code><\/pre><\/div>\n<div class=\"dd-vsc-status\"><span>\u2387 main<\/span><span>Ln 20, Col 1<\/span><span class=\"sp\"><\/span><span>Spaces: 4<\/span><span>UTF-8<\/span><span>LF<\/span><span>Python<\/span><\/div>\n<\/div>\n<\/div>\n<p class=\"dd-vsc-hint\">Same idea in Python. Open <strong>test_price.py<\/strong> and press <strong>\u25b6 Run<\/strong>.<\/p>\n\n<h2 id=\"local-pipeline\">Your first pipeline: a shell script<\/h2>\n<p>Before we use any CI tool, let us build a pipeline with nothing but a shell script. This shows that a pipeline is not magic: it is just <strong>a list of commands that must all succeed, in order<\/strong>. The line <code>set -euo pipefail<\/code> tells Bash to stop at the first failing command, which gives us the \u201cstop the line\u201d behaviour.<\/p>\n<div class=\"dd-vsc\" role=\"group\" aria-label=\"Code editor: ci.sh\">\n<input type=\"radio\" name=\"v3\" id=\"v3f1\" class=\"f1\" checked>\n<input type=\"checkbox\" id=\"v3r1\" class=\"r1\">\n<div class=\"dd-vsc-bar\"><span class=\"dd-dots\"><i><\/i><i><\/i><i><\/i><\/span><span class=\"dd-vsc-title\">ci.sh \u2014 devops-part1 \u2014 Visual Studio Code<\/span><\/div>\n<div class=\"dd-vsc-tabs\">\n<label for=\"v3f1\" class=\"t1\"><b class=\"ic sh\">$_<\/b>ci.sh<\/label>\n<label for=\"v3r1\" class=\"run run1\" title=\"Show the output in the terminal\">\u25b6 Run<\/label>\n<\/div>\n<div class=\"dd-vsc-pane p1\">\n<div class=\"dd-vsc-crumbs\">devops-part1 \u203a ci.sh<\/div>\n<pre class=\"dd-vsc-code\"><code><span class=\"l\"><span class=\"c\">#!\/usr\/bin\/env bash<\/span><\/span>\n<span class=\"l\"><span class=\"c\"># ci.sh - a tiny \"pipeline\" you can run on your own laptop.<\/span><\/span>\n<span class=\"l\"><span class=\"c\"># Each stage must pass before the next one starts.<\/span><\/span>\n<span class=\"l\"><span class=\"nb\">set<\/span> -euo pipefail<\/span>\n<span class=\"l\"><\/span>\n<span class=\"l\"><span class=\"nb\">echo<\/span> <span class=\"s\">\"\u25b6 Stage 1\/4: Install\"<\/span><\/span>\n<span class=\"l\">npm ci --silent<\/span>\n<span class=\"l\"><\/span>\n<span class=\"l\"><span class=\"nb\">echo<\/span> <span class=\"s\">\"\u25b6 Stage 2\/4: Lint (syntax check)\"<\/span><\/span>\n<span class=\"l\">npm run --silent lint<\/span>\n<span class=\"l\"><\/span>\n<span class=\"l\"><span class=\"nb\">echo<\/span> <span class=\"s\">\"\u25b6 Stage 3\/4: Test\"<\/span><\/span>\n<span class=\"l\">npm <span class=\"nb\">test<\/span> --silent<\/span>\n<span class=\"l\"><\/span>\n<span class=\"l\"><span class=\"nb\">echo<\/span> <span class=\"s\">\"\u25b6 Stage 4\/4: Build\"<\/span><\/span>\n<span class=\"l\">npm run --silent build<\/span>\n<span class=\"l\"><span class=\"nb\">echo<\/span> <span class=\"s\">\"\u2705 Pipeline passed. Build output is in .\/dist\"<\/span><\/span><\/code><\/pre>\n<div class=\"dd-vsc-term\"><div class=\"dd-term-head\"><span>TERMINAL<\/span><span>OUTPUT<\/span><span>PROBLEMS<\/span><span class=\"dd-term-note\">Real output<\/span><\/div><pre><code><span class=\"gp\">$<\/span> .\/ci.sh\n\u25b6 Stage 1\/4: Install\n\u25b6 Stage 2\/4: Lint (syntax check)\n\u25b6 Stage 3\/4: Test\n\u2714 adds 18% GST to the cart total (1.131146ms)\n\u2714 an empty cart costs nothing (0.188576ms)\n\u2714 rejects bad input (0.398218ms)\n\u2139 tests 3\n\u2139 suites 0\n\u2139 pass 3\n\u2139 fail 0\n\u2139 cancelled 0\n\u2139 skipped 0\n\u2139 todo 0\n\u2139 duration_ms 114.566688\n\u25b6 Stage 4\/4: Build\n\u2705 Pipeline passed. Build output is in .\/dist<\/code><\/pre><\/div>\n<div class=\"dd-vsc-status\"><span>\u2387 main<\/span><span>Ln 17, Col 1<\/span><span class=\"sp\"><\/span><span>Spaces: 2<\/span><span>UTF-8<\/span><span>LF<\/span><span>Shell Script<\/span><\/div>\n<\/div>\n<\/div>\n<p class=\"dd-vsc-hint\">Press <strong>\u25b6 Run<\/strong> to see the pipeline pass all four stages.<\/p>\n<p>Make the file executable once with <code>chmod +x ci.sh<\/code>. Now let us see what happens when someone makes a mistake. Change <code>GST_RATE<\/code> to <code>0.12<\/code> in <code>src\/price.js<\/code> and run the pipeline again:<\/p>\n<div class=\"dd-vsc dd-vsc-termonly\" role=\"group\" aria-label=\"Terminal: devops-part1 \u2014 bash (after a bad change)\">\n<div class=\"dd-vsc-bar\"><span class=\"dd-dots\"><i><\/i><i><\/i><i><\/i><\/span><span class=\"dd-vsc-title\">devops-part1 \u2014 bash (after a bad change)<\/span><\/div>\n<pre class=\"dd-vsc-code\"><code><span class=\"l\"><span class=\"c\"># A teammate changes GST_RATE from 0.18 to 0.12 by mistake...<\/span><\/span>\n<span class=\"l\"><span class=\"gp\">$<\/span> .\/ci.sh<\/span>\n<span class=\"l\">\u25b6 Stage 1\/4: Install<\/span>\n<span class=\"l\">\u25b6 Stage 2\/4: Lint (syntax check)<\/span>\n<span class=\"l\">\u25b6 Stage 3\/4: Test<\/span>\n<span class=\"l\">\u2716 adds 18% GST to the cart total (1.492308ms)<\/span>\n<span class=\"l\">\u2714 an empty cart costs nothing (0.19392ms)<\/span>\n<span class=\"l\">\u2714 rejects bad input (0.356971ms)<\/span>\n<span class=\"l\">\u2139 tests 3<\/span>\n<span class=\"l\">\u2139 suites 0<\/span>\n<span class=\"l\">\u2139 pass 2<\/span>\n<span class=\"l\">\u2139 fail 1<\/span>\n<span class=\"l\">\u2139 cancelled 0<\/span>\n<span class=\"l\">\u2139 skipped 0<\/span>\n<span class=\"l\">\u2139 todo 0<\/span>\n<span class=\"l\">\u2139 duration_ms 96.820684<\/span>\n<span class=\"l\"><\/span>\n<span class=\"l\">\u2716 failing tests:<\/span>\n<span class=\"l\"><\/span>\n<span class=\"l\">test at test\/price.test.js:5:1<\/span>\n<span class=\"l\">\u2716 adds 18% GST to the cart total (1.492308ms)<\/span>\n<span class=\"l\">  AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:<\/span>\n<span class=\"l\">  <\/span>\n<span class=\"l\">  280 !== 295<\/span>\n<span class=\"l\">  ... (stack trace trimmed)<\/span>\n<span class=\"l\"><\/span>\n<span class=\"l\"><span class=\"gp\">$<\/span> echo $?   <span class=\"c\"># exit code 1 = failure, so the pipeline stops<\/span><\/span>\n<span class=\"l\">1<\/span><\/code><\/pre>\n<\/div>\n<p>Look closely: <strong>Stage 4 (Build) never ran<\/strong>. The test caught the bug, the script exited with code <code>1<\/code>, and nothing was built. In a real pipeline, that also means nothing gets deployed. Change the value back to <code>0.18<\/code> and the pipeline is green again.<\/p>\n<div class=\"dd-note\">Every CI tool decides \u201cpass\u201d or \u201cfail\u201d using the <strong>exit code<\/strong> of each command: <code>0<\/code> means success, anything else means failure. If your test command always exits with <code>0<\/code>, your pipeline will never catch anything.<\/div>\n\n<h2 id=\"github-actions\">The same pipeline on GitHub Actions<\/h2>\n<p>A script on your laptop only runs when you remember to run it. The real power of CI comes when a server runs it <strong>automatically for every push and every pull request<\/strong>, for every person on the team. Let us move our pipeline to <a href=\"https:\/\/docs.github.com\/en\/actions\" target=\"_blank\" rel=\"noopener\">GitHub Actions<\/a>, the free CI\/CD service built into GitHub.<\/p>\n<p>Create a file at <code>.github\/workflows\/ci.yml<\/code>. GitHub automatically finds every YAML file in that folder:<\/p>\n<div class=\"dd-vsc\" role=\"group\" aria-label=\"Code editor: ci.yml, python-ci.yml\">\n<input type=\"radio\" name=\"v4\" id=\"v4f1\" class=\"f1\" checked>\n<input type=\"radio\" name=\"v4\" id=\"v4f2\" class=\"f2\">\n<div class=\"dd-vsc-bar\"><span class=\"dd-dots\"><i><\/i><i><\/i><i><\/i><\/span><span class=\"dd-vsc-title\">2 files \u2014 devops-part1 \u2014 Visual Studio Code<\/span><\/div>\n<div class=\"dd-vsc-tabs\">\n<label for=\"v4f1\" class=\"t1\"><b class=\"ic yml\">YML<\/b>ci.yml<\/label>\n<label for=\"v4f2\" class=\"t2\"><b class=\"ic yml\">YML<\/b>python-ci.yml<\/label>\n<\/div>\n<div class=\"dd-vsc-pane p1\">\n<div class=\"dd-vsc-crumbs\">devops-part1 \u203a .github \u203a workflows \u203a ci.yml<\/div>\n<pre class=\"dd-vsc-code\"><code><span class=\"l\"><span class=\"c\"># .github\/workflows\/ci.yml - runs our pipeline on GitHub's servers<\/span><\/span>\n<span class=\"l\"><span class=\"kc\">name<\/span>: CI<\/span>\n<span class=\"l\"><\/span>\n<span class=\"l\"><span class=\"kc\">on<\/span>:<\/span>\n<span class=\"l\">  <span class=\"kc\">push<\/span>:<\/span>\n<span class=\"l\">    <span class=\"kc\">branches<\/span>: [<span class=\"n\">main<\/span>]        <span class=\"c\"># every push to main<\/span><\/span>\n<span class=\"l\">  <span class=\"kc\">pull_request<\/span>:<\/span>\n<span class=\"l\">    <span class=\"kc\">branches<\/span>: [<span class=\"n\">main<\/span>]        <span class=\"c\"># every pull request into main<\/span><\/span>\n<span class=\"l\"><\/span>\n<span class=\"l\"><span class=\"kc\">jobs<\/span>:<\/span>\n<span class=\"l\">  <span class=\"kc\">build-and-test<\/span>:<\/span>\n<span class=\"l\">    <span class=\"kc\">runs-on<\/span>: ubuntu-latest  <span class=\"c\"># a fresh Linux machine for every run<\/span><\/span>\n<span class=\"l\">    <span class=\"kc\">steps<\/span>:<\/span>\n<span class=\"l\">      - <span class=\"kc\">name<\/span>: Check out the code<\/span>\n<span class=\"l\">        <span class=\"kc\">uses<\/span>: actions\/checkout@v6<\/span>\n<span class=\"l\"><\/span>\n<span class=\"l\">      - <span class=\"kc\">name<\/span>: Set up Node.js<\/span>\n<span class=\"l\">        <span class=\"kc\">uses<\/span>: actions\/setup-node@v6<\/span>\n<span class=\"l\">        <span class=\"kc\">with<\/span>:<\/span>\n<span class=\"l\">          <span class=\"kc\">node-version<\/span>: 24<\/span>\n<span class=\"l\">          <span class=\"kc\">cache<\/span>: npm<\/span>\n<span class=\"l\"><\/span>\n<span class=\"l\">      - <span class=\"kc\">name<\/span>: Install dependencies<\/span>\n<span class=\"l\">        <span class=\"kc\">run<\/span>: npm ci<\/span>\n<span class=\"l\"><\/span>\n<span class=\"l\">      - <span class=\"kc\">name<\/span>: Lint<\/span>\n<span class=\"l\">        <span class=\"kc\">run<\/span>: npm run lint<\/span>\n<span class=\"l\"><\/span>\n<span class=\"l\">      - <span class=\"kc\">name<\/span>: Test<\/span>\n<span class=\"l\">        <span class=\"kc\">run<\/span>: npm test<\/span>\n<span class=\"l\"><\/span>\n<span class=\"l\">      - <span class=\"kc\">name<\/span>: Build<\/span>\n<span class=\"l\">        <span class=\"kc\">run<\/span>: npm run build<\/span>\n<span class=\"l\"><\/span>\n<span class=\"l\">      - <span class=\"kc\">name<\/span>: Save the build as an artifact<\/span>\n<span class=\"l\">        <span class=\"kc\">uses<\/span>: actions\/upload-artifact@v6<\/span>\n<span class=\"l\">        <span class=\"kc\">with<\/span>:<\/span>\n<span class=\"l\">          <span class=\"kc\">name<\/span>: dist<\/span>\n<span class=\"l\">          <span class=\"kc\">path<\/span>: dist\/<\/span><\/code><\/pre>\n<div class=\"dd-vsc-status\"><span>\u2387 main<\/span><span>Ln 39, Col 1<\/span><span class=\"sp\"><\/span><span>Spaces: 2<\/span><span>UTF-8<\/span><span>LF<\/span><span>YAML<\/span><\/div>\n<\/div>\n<div class=\"dd-vsc-pane p2\">\n<div class=\"dd-vsc-crumbs\">devops-part1 \u203a .github \u203a workflows \u203a python-ci.yml<\/div>\n<pre class=\"dd-vsc-code\"><code><span class=\"l\"><span class=\"c\"># .github\/workflows\/python-ci.yml - the same idea for a Python project<\/span><\/span>\n<span class=\"l\"><span class=\"kc\">name<\/span>: Python CI<\/span>\n<span class=\"l\"><\/span>\n<span class=\"l\"><span class=\"kc\">on<\/span>:<\/span>\n<span class=\"l\">  <span class=\"kc\">push<\/span>:<\/span>\n<span class=\"l\">    <span class=\"kc\">branches<\/span>: [<span class=\"n\">main<\/span>]<\/span>\n<span class=\"l\">  <span class=\"kc\">pull_request<\/span>:<\/span>\n<span class=\"l\">    <span class=\"kc\">branches<\/span>: [<span class=\"n\">main<\/span>]<\/span>\n<span class=\"l\"><\/span>\n<span class=\"l\"><span class=\"kc\">jobs<\/span>:<\/span>\n<span class=\"l\">  <span class=\"kc\">test<\/span>:<\/span>\n<span class=\"l\">    <span class=\"kc\">runs-on<\/span>: ubuntu-latest<\/span>\n<span class=\"l\">    <span class=\"kc\">steps<\/span>:<\/span>\n<span class=\"l\">      - <span class=\"kc\">uses<\/span>: actions\/checkout@v6<\/span>\n<span class=\"l\"><\/span>\n<span class=\"l\">      - <span class=\"kc\">name<\/span>: Set up Python<\/span>\n<span class=\"l\">        <span class=\"kc\">uses<\/span>: actions\/setup-python@v6<\/span>\n<span class=\"l\">        <span class=\"kc\">with<\/span>:<\/span>\n<span class=\"l\">          <span class=\"kc\">python-version<\/span>: <span class=\"s\">\"3.13\"<\/span><\/span>\n<span class=\"l\"><\/span>\n<span class=\"l\">      - <span class=\"kc\">name<\/span>: Run the tests<\/span>\n<span class=\"l\">        <span class=\"kc\">run<\/span>: python -m unittest -v<\/span><\/code><\/pre>\n<div class=\"dd-vsc-status\"><span>\u2387 main<\/span><span>Ln 22, Col 1<\/span><span class=\"sp\"><\/span><span>Spaces: 2<\/span><span>UTF-8<\/span><span>LF<\/span><span>YAML<\/span><\/div>\n<\/div>\n<\/div>\n<p class=\"dd-vsc-hint\">Two tabs: the Node.js workflow and the same idea for a Python project. Both live in the <code>.github\/workflows\/<\/code> folder.<\/p>\n<p>Let us read the Node.js workflow line by line:<\/p>\n<ul>\n<li><code>on:<\/code> is the <strong>trigger<\/strong>. This workflow runs on every push to <code>main<\/code> and on every pull request that targets <code>main<\/code>.<\/li>\n<li><code>jobs:<\/code> holds one job called <code>build-and-test<\/code>. <code>runs-on: ubuntu-latest<\/code> asks GitHub for a fresh Linux runner, so every run starts from a clean machine.<\/li>\n<li><code>actions\/checkout<\/code> downloads your code onto the runner. <code>actions\/setup-node<\/code> installs Node.js 24 and caches npm downloads to make later runs faster.<\/li>\n<li>The <code>run:<\/code> steps are the same commands as our <code>ci.sh<\/code>: install, lint, test and build. If any step fails, the job stops and is marked red.<\/li>\n<li><code>actions\/upload-artifact<\/code> saves the <code>dist\/<\/code> folder so you (or a later deploy job) can download exactly what was tested.<\/li>\n<\/ul>\n<p>Now commit and push:<\/p>\n<div class=\"dd-vsc dd-vsc-termonly\" role=\"group\" aria-label=\"Terminal: devops-part1 \u2014 bash\">\n<div class=\"dd-vsc-bar\"><span class=\"dd-dots\"><i><\/i><i><\/i><i><\/i><\/span><span class=\"dd-vsc-title\">devops-part1 \u2014 bash<\/span><\/div>\n<pre class=\"dd-vsc-code\"><code><span class=\"l\"><span class=\"c\"># Commit the code and the workflow, then push to GitHub<\/span><\/span>\n<span class=\"l\"><span class=\"gp\">$<\/span> git add .<\/span>\n<span class=\"l\"><span class=\"gp\">$<\/span> git commit -m \"Add price module, tests and CI workflow\"<\/span>\n<span class=\"l\"><span class=\"gp\">$<\/span> git branch -M main<\/span>\n<span class=\"l\"><span class=\"gp\">$<\/span> git remote add origin https:\/\/github.com\/&lt;your-username&gt;\/devops-part1.git<\/span>\n<span class=\"l\"><span class=\"gp\">$<\/span> git push -u origin main<\/span>\n<span class=\"l\"><\/span>\n<span class=\"l\"><span class=\"c\"># Now open your repo on GitHub \u2192 the \"Actions\" tab<\/span><\/span>\n<span class=\"l\"><span class=\"c\"># You will see the \"CI\" workflow running for this push<\/span><\/span><\/code><\/pre>\n<\/div>\n<p>Open the <strong>Actions<\/strong> tab of your repository and you will see the run with a yellow dot (running), then a green tick (passed) or a red cross (failed). Open a pull request with the 0.12 bug and GitHub will show the failing check right on the PR, before anyone merges it. That is continuous integration in action.<\/p>\n<div class=\"dd-tip\"><strong>Keep action versions current.<\/strong> The <code>@v6<\/code> after each action is its major version. Check each action&#8217;s GitHub page now and then for a newer major version, and let Dependabot open update PRs for you (we set this up later in the series). Want a deeper GitHub Actions walkthrough right now? Read our <a href=\"https:\/\/devdojo.co.in\/?p=176\">GitHub Actions CI\/CD for Node.js beginner&#8217;s guide<\/a>; Part 5 and Part 12 of this series go even further.<\/div>\n<\/div>\n\n\n\n<div class=\"dd-post\">\n<h2 id=\"tools\">The DevOps tools map<\/h2>\n<p>New learners often feel lost in the huge list of DevOps tools. The good news: you only need <strong>one tool per job<\/strong> to get started, and the ideas carry over between tools. Here is a simple map:<\/p>\n<div class=\"dd-tablewrap\"><table>\n<thead><tr><th>Job to do<\/th><th>Popular tools<\/th><th>Covered in<\/th><\/tr><\/thead>\n<tbody>\n<tr><td>Version control<\/td><td>Git, GitHub, GitLab, Bitbucket<\/td><td>Part 3<\/td><\/tr>\n<tr><td>CI\/CD pipelines<\/td><td>GitHub Actions, GitLab CI\/CD, Jenkins, CircleCI, Azure Pipelines<\/td><td>Parts 5, 12, 13<\/td><\/tr>\n<tr><td>Containers<\/td><td>Docker, Podman<\/td><td>Parts 6\u20138<\/td><\/tr>\n<tr><td>Infrastructure as code<\/td><td>Terraform, OpenTofu, Pulumi, Ansible<\/td><td>Parts 14\u201315<\/td><\/tr>\n<tr><td>Orchestration and GitOps<\/td><td>Kubernetes, Helm, Argo CD, Flux<\/td><td>Parts 16\u201318<\/td><\/tr>\n<tr><td>Security<\/td><td>CodeQL, Trivy, Dependabot, Sigstore<\/td><td>Parts 21\u201322<\/td><\/tr>\n<tr><td>Monitoring<\/td><td>Prometheus, Grafana, OpenTelemetry<\/td><td>Parts 23\u201324<\/td><\/tr>\n<\/tbody><\/table><\/div>\n<p>If you want a sneak peek at containers, we already have a hands-on <a href=\"https:\/\/devdojo.co.in\/?p=188\">Docker Compose tutorial<\/a> and a <a href=\"https:\/\/devdojo.co.in\/?p=209\">Kubernetes tutorial for beginners<\/a>.<\/p>\n\n<h2 id=\"dora-metrics\">Measuring DevOps: the DORA metrics<\/h2>\n<p>How do you know if a team is \u201cgood at DevOps\u201d? The most widely used answer comes from <a href=\"https:\/\/dora.dev\/\" target=\"_blank\" rel=\"noopener\">DORA<\/a> (DevOps Research and Assessment), a research programme that has studied thousands of teams for over ten years. It tracks a small set of <strong>software delivery metrics<\/strong>. They started as four \u201ckey metrics\u201d, and DORA now also tracks a fifth one, deployment rework rate:<\/p>\n<div class=\"dd-cards\">\n<div class=\"dd-card\"><b>\ud83d\ude80 Deployment frequency<\/b>How often you deploy to production. Strong teams deploy on demand, often many times a day.<\/div>\n<div class=\"dd-card\"><b>\u23f1\ufe0f Change lead time<\/b>Time from a commit to that change running in production.<\/div>\n<div class=\"dd-card\"><b>\ud83d\udca5 Change fail rate<\/b>The share of deployments that cause a failure and need a fix or rollback.<\/div>\n<div class=\"dd-card\"><b>\ud83e\ude79 Failed deployment recovery time<\/b>How long it takes to recover when a deployment goes wrong.<\/div>\n<div class=\"dd-card\"><b>\ud83d\udd01 Deployment rework rate<\/b>The share of deployments that were unplanned, made only to fix a problem in production.<\/div>\n<\/div>\n<p>The two speed metrics (frequency and lead time) and the stability metrics (fail rate, recovery time, rework) usually <strong>improve together<\/strong>. Small, automated, well-tested changes are both faster <em>and<\/em> safer. That is the core promise of CI\/CD. We dive into measuring these numbers in Part 29.<\/p>\n\n<h2 id=\"common-errors\">Common errors and fixes<\/h2>\n<div class=\"dd-tablewrap\"><table>\n<thead><tr><th>Problem<\/th><th>Why it happens<\/th><th>Fix<\/th><\/tr><\/thead>\n<tbody>\n<tr><td>Workflow never runs on GitHub<\/td><td>File is in the wrong folder, or the branch name in <code>on:<\/code> does not match (e.g. <code>master<\/code> vs <code>main<\/code>).<\/td><td>Put it in <code>.github\/workflows\/<\/code> exactly, and check your default branch name.<\/td><\/tr>\n<tr><td><code>npm ci<\/code> fails: \u201ccan only install with an existing package-lock.json\u201d<\/td><td>The lock file was never created or not committed.<\/td><td>Run <code>npm install<\/code> locally and commit <code>package-lock.json<\/code>.<\/td><\/tr>\n<tr><td>Tests pass locally but fail in CI<\/td><td>Different Node.js\/Python version, missing environment variable, or a test that depends on your timezone or local files.<\/td><td>Pin the version in the workflow, pass needed variables, and make tests self-contained.<\/td><\/tr>\n<tr><td><code>Permission denied: .\/ci.sh<\/code><\/td><td>The script is not executable.<\/td><td>Run <code>chmod +x ci.sh<\/code> and commit (Git stores the executable bit).<\/td><\/tr>\n<tr><td>YAML error: \u201cmapping values are not allowed here\u201d<\/td><td>Wrong indentation or a tab character in the YAML file.<\/td><td>Use 2 spaces, never tabs. A YAML extension in VS Code highlights mistakes.<\/td><\/tr>\n<tr><td>Pipeline is green but the bug still shipped<\/td><td>No test covered that case, or a command hid its failure (exit code 0).<\/td><td>Add a test for the bug first, and use <code>set -euo pipefail<\/code> in scripts.<\/td><\/tr>\n<tr><td>A password appears in the build log<\/td><td>Secret was hard-coded or printed with <code>echo<\/code>.<\/td><td>Store it in repository <strong>Secrets<\/strong> and read it as <code>${{ secrets.NAME }}<\/code>. Rotate the leaked value.<\/td><\/tr>\n<\/tbody><\/table><\/div>\n\n<h2 id=\"best-practices\">Best practices for beginners<\/h2>\n<ul>\n<li><strong>Commit small and often.<\/strong> Merge to <code>main<\/code> at least once a day. Small changes are easy to test and easy to undo.<\/li>\n<li><strong>Keep the pipeline fast.<\/strong> Aim for CI feedback in under 10 minutes. Slow pipelines get ignored.<\/li>\n<li><strong>Fix a red build first.<\/strong> A broken main branch blocks everyone. Treat it as the team&#8217;s top priority.<\/li>\n<li><strong>Build once, deploy many times.<\/strong> Create one artifact and promote the same one to staging and production.<\/li>\n<li><strong>Make pipelines code.<\/strong> Keep workflow files in Git, review them in pull requests like any other code.<\/li>\n<li><strong>Never put secrets in code.<\/strong> Use the secret store of your CI tool or a secrets manager.<\/li>\n<li><strong>Protect the main branch.<\/strong> Require the CI check to pass before a pull request can be merged.<\/li>\n<\/ul>\n\n<h2 id=\"practice\">Practice task<\/h2>\n<div class=\"dd-tip\">\n<p><strong>Your mission (about 30 minutes):<\/strong><\/p>\n<ol>\n<li>Create the <code>devops-part1<\/code> project from this post and run <code>.\/ci.sh<\/code> until it is green.<\/li>\n<li>Add a <strong>fourth test<\/strong>: a cart with <code>{ price: 99.99, qty: 3 }<\/code> should cost <code>353.96<\/code> (check the rounding yourself first).<\/li>\n<li>Push the project to a new GitHub repository with the <code>ci.yml<\/code> workflow and get a green tick in the Actions tab.<\/li>\n<li>Open a pull request that breaks the GST rate. Confirm the check turns red on the PR, then fix it.<\/li>\n<li><em>Bonus:<\/em> in your repository settings, add a branch protection rule (or ruleset) for <code>main<\/code> that requires the CI check to pass before merging.<\/li>\n<\/ol>\n<\/div>\n\n<h2 id=\"faq\">Frequently asked questions<\/h2>\n<details><summary>Is DevOps a tool, a job title or a culture?<\/summary><p>Mainly a culture and a set of practices. Tools support it, and many companies also have \u201cDevOps engineer\u201d or \u201cplatform engineer\u201d roles whose job is to build pipelines and infrastructure for other teams. But every developer on a DevOps team shares responsibility for shipping and running the software.<\/p><\/details>\n<details><summary>What is the difference between CI and CD?<\/summary><p>CI (continuous integration) automatically builds and tests every change. CD takes the tested result further: continuous delivery keeps it always ready to release with a manual approval, and continuous deployment releases it to production automatically.<\/p><\/details>\n<details><summary>Do I need to learn Linux for DevOps?<\/summary><p>Yes, basic Linux and shell skills are very useful because most servers, containers and CI runners use Linux. You do not need to be an expert. Part 2 of this series covers exactly the commands you need.<\/p><\/details>\n<details><summary>Which CI\/CD tool should a beginner learn first?<\/summary><p>GitHub Actions is a great first choice: it is built into GitHub, free for public repositories, and uses simple YAML. The concepts (triggers, jobs, steps, artifacts, secrets) transfer directly to GitLab CI\/CD, Jenkins and others.<\/p><\/details>\n<details><summary>Can a fresher get a DevOps job?<\/summary><p>Yes. Many freshers start as developers or support engineers and grow into DevOps roles. Build a few projects with real pipelines (test, Docker image, deploy), put them on GitHub, and be ready to explain each step. Following this series end to end will give you that portfolio.<\/p><\/details>\n\n<h2 id=\"conclusion\">Conclusion<\/h2>\n<p>You now know <strong>what DevOps is<\/strong>: a culture where development and operations work as one team, ship small changes often, and automate everything they can. You learned how <strong>CI\/CD<\/strong> fits in (continuous integration, continuous delivery and continuous deployment), the parts of a pipeline (triggers, runners, jobs, steps and artifacts), and how teams measure success with the DORA metrics. Most importantly, you built a real pipeline twice: once as a shell script and once on GitHub Actions, and you saw it stop a bug before it could ship.<\/p>\n\n<div class=\"dd-next\"><strong>Next part \u2013 DevOps CI\/CD Part 2: Linux and Shell Basics Every DevOps Engineer Needs.<\/strong> Pipelines, servers and containers all speak Linux. We will learn the files, permissions, processes, environment variables and shell scripting skills you will use in every later part.<\/div>\n\n<div class=\"dd-cta\">\n<h3>New posts every day on DevDojo<\/h3>\n<p>Follow the full <strong>DevOps CI\/CD series<\/strong> \u2013 30 parts from \u201cwhat is DevOps\u201d to a complete pipeline from commit to production. Bookmark <a href=\"https:\/\/devdojo.co.in\/\">devdojo.co.in<\/a> and tell us in the comments which CI\/CD tool your team uses.<\/p>\n<\/div>\n<\/div>\n\n","protected":false},"excerpt":{"rendered":"<p>What is DevOps? Learn DevOps and CI\/CD in simple words: the DevOps lifecycle, CI vs CD, pipeline basics, and build your first GitHub Actions pipeline.<\/p>\n","protected":false},"author":1,"featured_media":228,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[57],"tags":[59,122,61,123,58,121],"class_list":["post-229","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-devops","tag-ci-cd","tag-continuous-integration","tag-devops","tag-devops-for-beginners","tag-github-actions","tag-series-devops-ci-cd"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.3 - aioseo.com -->\n\t<meta name=\"description\" content=\"What is DevOps? Learn DevOps and CI\/CD in simple words: the DevOps lifecycle, CI vs CD, pipeline basics, and build your first GitHub Actions pipeline.\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Lokendra\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/devdojo.co.in\/index.php\/2026\/10\/21\/devops-series-part-1-what-is-devops-ci-cd\/\" \/>\n\t\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.3\" \/>\n\t\t<meta property=\"og:locale\" content=\"en_US\" \/>\n\t\t<meta property=\"og:site_name\" content=\"DevDojo - Empowering Developers\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"What Is DevOps and How Does CI\/CD Work? (DevOps CI\/CD Part 1)\" \/>\n\t\t<meta property=\"og:description\" content=\"What is DevOps? Learn DevOps and CI\/CD in simple words: the DevOps lifecycle, CI vs CD, pipeline basics, and build your first GitHub Actions pipeline.\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/devdojo.co.in\/index.php\/2026\/10\/21\/devops-series-part-1-what-is-devops-ci-cd\/\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2026-10-21T14:21:01+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2026-10-21T14:21:03+00:00\" \/>\n\t\t<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n\t\t<meta name=\"twitter:title\" content=\"What Is DevOps and How Does CI\/CD Work? (DevOps CI\/CD Part 1)\" \/>\n\t\t<meta name=\"twitter:description\" content=\"What is DevOps? Learn DevOps and CI\/CD in simple words: the DevOps lifecycle, CI vs CD, pipeline basics, and build your first GitHub Actions pipeline.\" \/>\n\t\t<script type=\"application\/ld+json\" class=\"aioseo-schema\">\n\t\t\t{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"BlogPosting\",\"@id\":\"https:\\\/\\\/devdojo.co.in\\\/index.php\\\/2026\\\/10\\\/21\\\/devops-series-part-1-what-is-devops-ci-cd\\\/#blogposting\",\"name\":\"What Is DevOps? CI\\\/CD Explained for Beginners | DevDojo\",\"headline\":\"DevOps CI\\\/CD Part 1: What Is DevOps and How Does CI\\\/CD Work?\",\"author\":{\"@id\":\"https:\\\/\\\/devdojo.co.in\\\/index.php\\\/author\\\/lokendra\\\/#author\"},\"publisher\":{\"@id\":\"https:\\\/\\\/devdojo.co.in\\\/#organization\"},\"image\":{\"@type\":\"ImageObject\",\"url\":\"https:\\\/\\\/devdojo.co.in\\\/wp-content\\\/uploads\\\/2026\\\/10\\\/devops-series-part-1-what-is-devops-ci-cd.jpg\",\"width\":1200,\"height\":630,\"caption\":\"DevOps CI\\\/CD series Part 1 banner: what is DevOps and how CI\\\/CD works, with the DevOps infinity loop and a git push to deploy pipeline\"},\"datePublished\":\"2026-10-21T14:21:01+00:00\",\"dateModified\":\"2026-10-21T14:21:03+00:00\",\"inLanguage\":\"en-US\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/devdojo.co.in\\\/index.php\\\/2026\\\/10\\\/21\\\/devops-series-part-1-what-is-devops-ci-cd\\\/#webpage\"},\"isPartOf\":{\"@id\":\"https:\\\/\\\/devdojo.co.in\\\/index.php\\\/2026\\\/10\\\/21\\\/devops-series-part-1-what-is-devops-ci-cd\\\/#webpage\"},\"articleSection\":\"DevOps, CI\\\/CD, Continuous Integration, DevOps, DevOps for Beginners, GitHub Actions, Series: DevOps CI\\\/CD\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/devdojo.co.in\\\/index.php\\\/2026\\\/10\\\/21\\\/devops-series-part-1-what-is-devops-ci-cd\\\/#breadcrumblist\",\"itemListElement\":[{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/devdojo.co.in\\\/#listItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/devdojo.co.in\\\/\",\"nextItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/devdojo.co.in\\\/index.php\\\/category\\\/devops\\\/#listItem\",\"name\":\"DevOps\"}},{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/devdojo.co.in\\\/index.php\\\/category\\\/devops\\\/#listItem\",\"position\":2,\"name\":\"DevOps\",\"item\":\"https:\\\/\\\/devdojo.co.in\\\/index.php\\\/category\\\/devops\\\/\",\"nextItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/devdojo.co.in\\\/index.php\\\/2026\\\/10\\\/21\\\/devops-series-part-1-what-is-devops-ci-cd\\\/#listItem\",\"name\":\"DevOps CI\\\/CD Part 1: What Is DevOps and How Does CI\\\/CD Work?\"},\"previousItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/devdojo.co.in\\\/#listItem\",\"name\":\"Home\"}},{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/devdojo.co.in\\\/index.php\\\/2026\\\/10\\\/21\\\/devops-series-part-1-what-is-devops-ci-cd\\\/#listItem\",\"position\":3,\"name\":\"DevOps CI\\\/CD Part 1: What Is DevOps and How Does CI\\\/CD Work?\",\"previousItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/devdojo.co.in\\\/index.php\\\/category\\\/devops\\\/#listItem\",\"name\":\"DevOps\"}}]},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/devdojo.co.in\\\/#organization\",\"name\":\"DevDojo\",\"description\":\"Empowering Developers\",\"url\":\"https:\\\/\\\/devdojo.co.in\\\/\"},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/devdojo.co.in\\\/index.php\\\/author\\\/lokendra\\\/#author\",\"url\":\"https:\\\/\\\/devdojo.co.in\\\/index.php\\\/author\\\/lokendra\\\/\",\"name\":\"Lokendra\",\"image\":{\"@type\":\"ImageObject\",\"@id\":\"https:\\\/\\\/devdojo.co.in\\\/index.php\\\/2026\\\/10\\\/21\\\/devops-series-part-1-what-is-devops-ci-cd\\\/#authorImage\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/99f102f0cc9080237ce54b91304fd1b3b6fa29925cbaeba93cd796872e58b45c?s=96&d=mm&r=g\",\"width\":96,\"height\":96,\"caption\":\"Lokendra\"}},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/devdojo.co.in\\\/index.php\\\/2026\\\/10\\\/21\\\/devops-series-part-1-what-is-devops-ci-cd\\\/#webpage\",\"url\":\"https:\\\/\\\/devdojo.co.in\\\/index.php\\\/2026\\\/10\\\/21\\\/devops-series-part-1-what-is-devops-ci-cd\\\/\",\"name\":\"What Is DevOps? CI\\\/CD Explained for Beginners | DevDojo\",\"description\":\"What is DevOps? Learn DevOps and CI\\\/CD in simple words: the DevOps lifecycle, CI vs CD, pipeline basics, and build your first GitHub Actions pipeline.\",\"inLanguage\":\"en-US\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/devdojo.co.in\\\/#website\"},\"breadcrumb\":{\"@id\":\"https:\\\/\\\/devdojo.co.in\\\/index.php\\\/2026\\\/10\\\/21\\\/devops-series-part-1-what-is-devops-ci-cd\\\/#breadcrumblist\"},\"author\":{\"@id\":\"https:\\\/\\\/devdojo.co.in\\\/index.php\\\/author\\\/lokendra\\\/#author\"},\"creator\":{\"@id\":\"https:\\\/\\\/devdojo.co.in\\\/index.php\\\/author\\\/lokendra\\\/#author\"},\"image\":{\"@type\":\"ImageObject\",\"url\":\"https:\\\/\\\/devdojo.co.in\\\/wp-content\\\/uploads\\\/2026\\\/10\\\/devops-series-part-1-what-is-devops-ci-cd.jpg\",\"@id\":\"https:\\\/\\\/devdojo.co.in\\\/index.php\\\/2026\\\/10\\\/21\\\/devops-series-part-1-what-is-devops-ci-cd\\\/#mainImage\",\"width\":1200,\"height\":630,\"caption\":\"DevOps CI\\\/CD series Part 1 banner: what is DevOps and how CI\\\/CD works, with the DevOps infinity loop and a git push to deploy pipeline\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/devdojo.co.in\\\/index.php\\\/2026\\\/10\\\/21\\\/devops-series-part-1-what-is-devops-ci-cd\\\/#mainImage\"},\"datePublished\":\"2026-10-21T14:21:01+00:00\",\"dateModified\":\"2026-10-21T14:21:03+00:00\"},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/devdojo.co.in\\\/#website\",\"url\":\"https:\\\/\\\/devdojo.co.in\\\/\",\"name\":\"DevDojo\",\"description\":\"Empowering Developers\",\"inLanguage\":\"en-US\",\"publisher\":{\"@id\":\"https:\\\/\\\/devdojo.co.in\\\/#organization\"}}]}\n\t\t<\/script>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"What Is DevOps? CI\/CD Explained for Beginners | DevDojo","description":"What is DevOps? Learn DevOps and CI\/CD in simple words: the DevOps lifecycle, CI vs CD, pipeline basics, and build your first GitHub Actions pipeline.","canonical_url":"https:\/\/devdojo.co.in\/index.php\/2026\/10\/21\/devops-series-part-1-what-is-devops-ci-cd\/","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"BlogPosting","@id":"https:\/\/devdojo.co.in\/index.php\/2026\/10\/21\/devops-series-part-1-what-is-devops-ci-cd\/#blogposting","name":"What Is DevOps? CI\/CD Explained for Beginners | DevDojo","headline":"DevOps CI\/CD Part 1: What Is DevOps and How Does CI\/CD Work?","author":{"@id":"https:\/\/devdojo.co.in\/index.php\/author\/lokendra\/#author"},"publisher":{"@id":"https:\/\/devdojo.co.in\/#organization"},"image":{"@type":"ImageObject","url":"https:\/\/devdojo.co.in\/wp-content\/uploads\/2026\/10\/devops-series-part-1-what-is-devops-ci-cd.jpg","width":1200,"height":630,"caption":"DevOps CI\/CD series Part 1 banner: what is DevOps and how CI\/CD works, with the DevOps infinity loop and a git push to deploy pipeline"},"datePublished":"2026-10-21T14:21:01+00:00","dateModified":"2026-10-21T14:21:03+00:00","inLanguage":"en-US","mainEntityOfPage":{"@id":"https:\/\/devdojo.co.in\/index.php\/2026\/10\/21\/devops-series-part-1-what-is-devops-ci-cd\/#webpage"},"isPartOf":{"@id":"https:\/\/devdojo.co.in\/index.php\/2026\/10\/21\/devops-series-part-1-what-is-devops-ci-cd\/#webpage"},"articleSection":"DevOps, CI\/CD, Continuous Integration, DevOps, DevOps for Beginners, GitHub Actions, Series: DevOps CI\/CD"},{"@type":"BreadcrumbList","@id":"https:\/\/devdojo.co.in\/index.php\/2026\/10\/21\/devops-series-part-1-what-is-devops-ci-cd\/#breadcrumblist","itemListElement":[{"@type":"ListItem","@id":"https:\/\/devdojo.co.in\/#listItem","position":1,"name":"Home","item":"https:\/\/devdojo.co.in\/","nextItem":{"@type":"ListItem","@id":"https:\/\/devdojo.co.in\/index.php\/category\/devops\/#listItem","name":"DevOps"}},{"@type":"ListItem","@id":"https:\/\/devdojo.co.in\/index.php\/category\/devops\/#listItem","position":2,"name":"DevOps","item":"https:\/\/devdojo.co.in\/index.php\/category\/devops\/","nextItem":{"@type":"ListItem","@id":"https:\/\/devdojo.co.in\/index.php\/2026\/10\/21\/devops-series-part-1-what-is-devops-ci-cd\/#listItem","name":"DevOps CI\/CD Part 1: What Is DevOps and How Does CI\/CD Work?"},"previousItem":{"@type":"ListItem","@id":"https:\/\/devdojo.co.in\/#listItem","name":"Home"}},{"@type":"ListItem","@id":"https:\/\/devdojo.co.in\/index.php\/2026\/10\/21\/devops-series-part-1-what-is-devops-ci-cd\/#listItem","position":3,"name":"DevOps CI\/CD Part 1: What Is DevOps and How Does CI\/CD Work?","previousItem":{"@type":"ListItem","@id":"https:\/\/devdojo.co.in\/index.php\/category\/devops\/#listItem","name":"DevOps"}}]},{"@type":"Organization","@id":"https:\/\/devdojo.co.in\/#organization","name":"DevDojo","description":"Empowering Developers","url":"https:\/\/devdojo.co.in\/"},{"@type":"Person","@id":"https:\/\/devdojo.co.in\/index.php\/author\/lokendra\/#author","url":"https:\/\/devdojo.co.in\/index.php\/author\/lokendra\/","name":"Lokendra","image":{"@type":"ImageObject","@id":"https:\/\/devdojo.co.in\/index.php\/2026\/10\/21\/devops-series-part-1-what-is-devops-ci-cd\/#authorImage","url":"https:\/\/secure.gravatar.com\/avatar\/99f102f0cc9080237ce54b91304fd1b3b6fa29925cbaeba93cd796872e58b45c?s=96&d=mm&r=g","width":96,"height":96,"caption":"Lokendra"}},{"@type":"WebPage","@id":"https:\/\/devdojo.co.in\/index.php\/2026\/10\/21\/devops-series-part-1-what-is-devops-ci-cd\/#webpage","url":"https:\/\/devdojo.co.in\/index.php\/2026\/10\/21\/devops-series-part-1-what-is-devops-ci-cd\/","name":"What Is DevOps? CI\/CD Explained for Beginners | DevDojo","description":"What is DevOps? Learn DevOps and CI\/CD in simple words: the DevOps lifecycle, CI vs CD, pipeline basics, and build your first GitHub Actions pipeline.","inLanguage":"en-US","isPartOf":{"@id":"https:\/\/devdojo.co.in\/#website"},"breadcrumb":{"@id":"https:\/\/devdojo.co.in\/index.php\/2026\/10\/21\/devops-series-part-1-what-is-devops-ci-cd\/#breadcrumblist"},"author":{"@id":"https:\/\/devdojo.co.in\/index.php\/author\/lokendra\/#author"},"creator":{"@id":"https:\/\/devdojo.co.in\/index.php\/author\/lokendra\/#author"},"image":{"@type":"ImageObject","url":"https:\/\/devdojo.co.in\/wp-content\/uploads\/2026\/10\/devops-series-part-1-what-is-devops-ci-cd.jpg","@id":"https:\/\/devdojo.co.in\/index.php\/2026\/10\/21\/devops-series-part-1-what-is-devops-ci-cd\/#mainImage","width":1200,"height":630,"caption":"DevOps CI\/CD series Part 1 banner: what is DevOps and how CI\/CD works, with the DevOps infinity loop and a git push to deploy pipeline"},"primaryImageOfPage":{"@id":"https:\/\/devdojo.co.in\/index.php\/2026\/10\/21\/devops-series-part-1-what-is-devops-ci-cd\/#mainImage"},"datePublished":"2026-10-21T14:21:01+00:00","dateModified":"2026-10-21T14:21:03+00:00"},{"@type":"WebSite","@id":"https:\/\/devdojo.co.in\/#website","url":"https:\/\/devdojo.co.in\/","name":"DevDojo","description":"Empowering Developers","inLanguage":"en-US","publisher":{"@id":"https:\/\/devdojo.co.in\/#organization"}}]},"og:locale":"en_US","og:site_name":"DevDojo - Empowering Developers","og:type":"article","og:title":"What Is DevOps and How Does CI\/CD Work? (DevOps CI\/CD Part 1)","og:description":"What is DevOps? Learn DevOps and CI\/CD in simple words: the DevOps lifecycle, CI vs CD, pipeline basics, and build your first GitHub Actions pipeline.","og:url":"https:\/\/devdojo.co.in\/index.php\/2026\/10\/21\/devops-series-part-1-what-is-devops-ci-cd\/","article:published_time":"2026-10-21T14:21:01+00:00","article:modified_time":"2026-10-21T14:21:03+00:00","twitter:card":"summary_large_image","twitter:title":"What Is DevOps and How Does CI\/CD Work? (DevOps CI\/CD Part 1)","twitter:description":"What is DevOps? Learn DevOps and CI\/CD in simple words: the DevOps lifecycle, CI vs CD, pipeline basics, and build your first GitHub Actions pipeline."},"aioseo_meta_data":{"post_id":"229","title":"What Is DevOps? CI\/CD Explained for Beginners | DevDojo","description":"What is DevOps? Learn DevOps and CI\/CD in simple words: the DevOps lifecycle, CI vs CD, pipeline basics, and build your first GitHub Actions pipeline.","keywords":null,"keyphrases":{"focus":{"keyphrase":"what is DevOps"},"additional":[]},"primary_term":null,"canonical_url":null,"og_title":"What Is DevOps and How Does CI\/CD Work? (DevOps CI\/CD Part 1)","og_description":"What is DevOps? Learn DevOps and CI\/CD in simple words: the DevOps lifecycle, CI vs CD, pipeline basics, and build your first GitHub Actions pipeline.","og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":"","og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"BlogPosting","isEnabled":true},"graphs":[]},"schema_type":"default","schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":"-1","robots_max_videopreview":"-1","robots_max_imagepreview":"large","priority":0,"frequency":"default","local_seo":null,"breadcrumb_settings":null,"limit_modified_date":false,"ai":{"faqs":[],"keyPoints":[],"schemas":[],"titles":[],"descriptions":[],"socialPosts":{"email":{"subject":"","preview":"","content":""},"linkedin":[],"twitter":[],"facebook":[],"instagram":[]}},"created":"2026-10-21 13:15:46","updated":"2026-10-21 17:17:06","focus_keyword":"what is DevOps","additional_keywords":null,"truseo_locale":null,"seo_analyzer_scan_date":null},"aioseo_breadcrumb":"<div class=\"aioseo-breadcrumbs\"><span class=\"aioseo-breadcrumb\">\n\t\t\t<a href=\"https:\/\/devdojo.co.in\/\" title=\"Home\">Home<\/a>\n\t\t<\/span><span class=\"aioseo-breadcrumb-separator\">\u00bb<\/span><span class=\"aioseo-breadcrumb\">\n\t\t\t<a href=\"https:\/\/devdojo.co.in\/index.php\/category\/devops\/\" title=\"DevOps\">DevOps<\/a>\n\t\t<\/span><span class=\"aioseo-breadcrumb-separator\">\u00bb<\/span><span class=\"aioseo-breadcrumb\">\n\t\t\tDevOps CI\/CD Part 1: What Is DevOps and How Does CI\/CD Work?\n\t\t<\/span><\/div>","aioseo_breadcrumb_json":[{"label":"Home","link":"https:\/\/devdojo.co.in\/"},{"label":"DevOps","link":"https:\/\/devdojo.co.in\/index.php\/category\/devops\/"},{"label":"DevOps CI\/CD Part 1: What Is DevOps and How Does CI\/CD Work?","link":"https:\/\/devdojo.co.in\/index.php\/2026\/10\/21\/devops-series-part-1-what-is-devops-ci-cd\/"}],"_links":{"self":[{"href":"https:\/\/devdojo.co.in\/index.php\/wp-json\/wp\/v2\/posts\/229","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devdojo.co.in\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devdojo.co.in\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devdojo.co.in\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/devdojo.co.in\/index.php\/wp-json\/wp\/v2\/comments?post=229"}],"version-history":[{"count":1,"href":"https:\/\/devdojo.co.in\/index.php\/wp-json\/wp\/v2\/posts\/229\/revisions"}],"predecessor-version":[{"id":230,"href":"https:\/\/devdojo.co.in\/index.php\/wp-json\/wp\/v2\/posts\/229\/revisions\/230"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devdojo.co.in\/index.php\/wp-json\/wp\/v2\/media\/228"}],"wp:attachment":[{"href":"https:\/\/devdojo.co.in\/index.php\/wp-json\/wp\/v2\/media?parent=229"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devdojo.co.in\/index.php\/wp-json\/wp\/v2\/categories?post=229"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devdojo.co.in\/index.php\/wp-json\/wp\/v2\/tags?post=229"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}