fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
8876fbf
fdbc4cc
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 | <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Azure DevOps & MLOps Masterclass</title>
<link rel="stylesheet" href="../shared/css/design-system.css">
<link rel="stylesheet" href="../shared/css/components.css">
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
:root {
--bg: #0f1419;
--surface: #1a1f2e;
--text: #e4e6eb;
--text-dim: #b0b7c3;
--cyan: #0078D4;
--orange: #ff6b35;
--green: #00ff88;
--yellow: #ffa500;
--azure: #0078D4;
--teal: #00b7c3;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background: var(--bg);
color: var(--text);
line-height: 1.6;
overflow-x: hidden;
}
.container {
max-width: 1400px;
margin: 0 auto;
padding: 20px;
}
header {
text-align: center;
margin-bottom: 40px;
padding: 30px 0;
border-bottom: 2px solid var(--azure);
}
h1 {
font-size: 2.5em;
background: linear-gradient(135deg, var(--azure), var(--teal));
background-clip: text;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
margin-bottom: 10px;
}
.subtitle {
color: var(--text-dim);
font-size: 1.1em;
}
.dashboard {
display: none;
}
.dashboard.active {
display: block;
}
.grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 25px;
margin: 40px 0;
}
.card {
background: linear-gradient(135deg, rgba(0, 120, 212, 0.1), rgba(0, 183, 195, 0.1));
border: 2px solid var(--azure);
border-radius: 12px;
padding: 30px;
cursor: pointer;
transition: all 0.3s ease;
text-align: center;
}
.card:hover {
transform: translateY(-5px);
box-shadow: 0 10px 30px rgba(0, 120, 212, 0.3);
border-color: var(--teal);
}
.card-icon {
font-size: 3em;
margin-bottom: 15px;
}
.card h3 {
color: var(--azure);
font-size: 1.5em;
margin-bottom: 10px;
}
.card p {
color: var(--text-dim);
font-size: 0.95em;
}
.category-label {
display: inline-block;
margin-top: 10px;
padding: 5px 12px;
background: rgba(0, 120, 212, 0.2);
border-radius: 20px;
font-size: 0.85em;
color: var(--green);
}
.module {
display: none;
}
.module.active {
display: block;
animation: fadeIn 0.3s ease;
}
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
.btn-back {
padding: 10px 20px;
background: var(--azure);
color: white;
border: none;
border-radius: 6px;
cursor: pointer;
font-weight: 600;
margin-bottom: 25px;
transition: all 0.3s ease;
}
.btn-back:hover {
background: var(--teal);
}
.tabs {
display: flex;
gap: 10px;
margin-bottom: 30px;
flex-wrap: wrap;
justify-content: center;
border-bottom: 1px solid rgba(0, 120, 212, 0.2);
padding-bottom: 15px;
overflow-x: auto;
}
.tab-btn {
padding: 10px 20px;
background: var(--surface);
color: var(--text);
border: 2px solid transparent;
border-radius: 6px;
cursor: pointer;
font-size: 0.95em;
transition: all 0.3s ease;
font-weight: 500;
white-space: nowrap;
}
.tab-btn:hover {
background: rgba(0, 120, 212, 0.1);
border-color: var(--azure);
}
.tab-btn.active {
background: var(--azure);
color: white;
border-color: var(--azure);
}
.tab {
display: none;
}
.tab.active {
display: block;
animation: fadeIn 0.3s ease;
}
.section {
background: var(--surface);
border: 1px solid rgba(0, 120, 212, 0.2);
border-radius: 10px;
padding: 30px;
margin-bottom: 25px;
transition: all 0.3s ease;
}
.section:hover {
border-color: var(--azure);
box-shadow: 0 0 20px rgba(0, 120, 212, 0.1);
}
h2 {
color: var(--azure);
font-size: 1.8em;
margin-bottom: 15px;
}
h3 {
color: var(--orange);
font-size: 1.3em;
margin-top: 20px;
margin-bottom: 12px;
}
h4 {
color: var(--green);
font-size: 1.1em;
margin-top: 15px;
margin-bottom: 10px;
}
p {
margin-bottom: 15px;
line-height: 1.8;
}
ul {
margin-left: 20px;
margin-bottom: 15px;
}
ul li {
margin-bottom: 8px;
}
.info-box {
background: rgba(0, 120, 212, 0.08);
border: 1px solid rgba(0, 120, 212, 0.2);
border-radius: 8px;
padding: 20px;
margin: 15px 0;
}
.box-title {
font-weight: bold;
color: var(--azure);
margin-bottom: 10px;
font-size: 1.1em;
}
.box-content {
color: var(--text-dim);
line-height: 1.8;
}
.warning-box {
background: rgba(255, 165, 0, 0.08);
border: 1px solid rgba(255, 165, 0, 0.3);
border-radius: 8px;
padding: 20px;
margin: 15px 0;
}
.warning-box .box-title {
color: var(--yellow);
}
table {
width: 100%;
border-collapse: collapse;
margin: 20px 0;
border-radius: 8px;
overflow: hidden;
}
th,
td {
padding: 12px 16px;
text-align: left;
border-bottom: 1px solid rgba(0, 120, 212, 0.15);
}
th {
background: rgba(0, 120, 212, 0.15);
color: var(--azure);
font-weight: 600;
}
td {
color: var(--text-dim);
}
tr:hover td {
background: rgba(0, 120, 212, 0.05);
}
.code-block {
background: #1e1e2e;
border: 1px solid rgba(0, 120, 212, 0.2);
border-radius: 8px;
padding: 20px;
margin: 15px 0;
font-family: 'Fira Code', 'Consolas', monospace;
font-size: 0.9em;
overflow-x: auto;
color: #cdd6f4;
line-height: 1.6;
}
.code-block .comment {
color: #6c7086;
}
.code-block .keyword {
color: #cba6f7;
}
.code-block .string {
color: #a6e3a1;
}
.code-block .key {
color: #89b4fa;
}
.formula {
background: rgba(0, 120, 212, 0.08);
padding: 20px;
border-radius: 8px;
margin: 15px 0;
border-left: 4px solid var(--azure);
font-family: 'Georgia', serif;
}
.callout {
padding: 20px;
border-radius: 8px;
margin: 15px 0;
border-left: 4px solid;
}
.callout.insight {
background: rgba(0, 255, 136, 0.05);
border-color: var(--green);
}
.callout.insight .callout-title {
color: var(--green);
font-weight: bold;
margin-bottom: 8px;
}
.callout.warning {
background: rgba(255, 165, 0, 0.05);
border-color: var(--yellow);
}
.callout.warning .callout-title {
color: var(--yellow);
font-weight: bold;
margin-bottom: 8px;
}
.pipeline-flow {
display: flex;
align-items: center;
gap: 0;
flex-wrap: wrap;
justify-content: center;
margin: 20px 0;
padding: 20px;
background: rgba(0, 120, 212, 0.05);
border-radius: 12px;
}
.pipeline-stage {
padding: 12px 20px;
border-radius: 8px;
font-weight: 600;
font-size: 0.85em;
text-align: center;
min-width: 100px;
}
.pipeline-arrow {
font-size: 1.5em;
color: var(--azure);
padding: 0 4px;
}
.interview-box {
background: rgba(163, 113, 247, 0.08);
border: 1px solid rgba(163, 113, 247, 0.25);
border-radius: 8px;
padding: 20px;
margin: 15px 0;
}
.interview-box .box-title {
color: #a371f7;
}
@media (max-width: 768px) {
.grid {
grid-template-columns: 1fr;
}
.pipeline-flow {
flex-direction: column;
}
.pipeline-arrow {
transform: rotate(90deg);
}
h1 {
font-size: 1.8em;
}
}
</style>
</head>
<body>
<div class="container">
<div class="dashboard active" id="dashboard">
<header>
<h1>βοΈ Azure DevOps & MLOps Masterclass</h1>
<p class="subtitle">CI/CD Pipelines Β· Containers Β· Kubernetes Β· MLOps β From Zero to Production</p>
</header>
<div class="grid" id="modulesGrid"></div>
</div>
<div id="modulesContainer"></div>
</div>
<script>
const modules = [
{id: "devops-fundamentals", title: "DevOps Fundamentals", icon: "π", category: "Foundations", color: "#0078D4", description: "CI/CD concepts, DevOps culture, and the shift to MLOps" },
{id: "azure-setup", title: "Azure DevOps Setup", icon: "βοΈ", category: "Foundations", color: "#0078D4", description: "Organizations, Projects, Repos, and Git workflows" },
{id: "infrastructure", title: "Infrastructure & Networking", icon: "π", category: "Infrastructure", color: "#00b7c3", description: "VPCs, Security Groups, VMs, and Azure networking" },
{id: "cicd-yaml", title: "CI/CD Pipeline (YAML)", icon: "π", category: "Pipeline", color: "#ff6b35", description: "YAML syntax, Triggers, Variables, Stages, Multi-stage pipelines" },
{id: "build-test", title: "Build & Test", icon: "π§ͺ", category: "Pipeline", color: "#ff6b35", description: "Maven, Unit Tests, SonarQube quality gates, Trivy scanning" },
{id: "docker", title: "Docker & Containers", icon: "π³", category: "Containers", color: "#2496ED", description: "Dockerfile, Build, Push to ACR, Image scanning" },
{id: "kubernetes", title: "Kubernetes & AKS", icon: "βΈοΈ", category: "Orchestration", color: "#326CE5", description: "AKS setup, Deployments, Services, Manifests, Helm" },
{id: "security", title: "Service Connections & Security", icon: "π", category: "Security", color: "#e74c3c", description: "Service Principals, RBAC, Key Vault, PAT tokens" },
{id: "mlops", title: "MLOps Pipeline", icon: "π€", category: "MLOps", color: "#a371f7", description: "ML lifecycle, Model versioning, Data drift, CT/CI/CD for ML" },
{id: "monitoring", title: "Monitoring & Automation", icon: "π", category: "Operations", color: "#2ecc71", description: "Deployment verification, Pipeline automation, Notifications" }
];
const MODULE_CONTENT = {
"devops-fundamentals": {
concepts: `
<h3>What is DevOps?</h3>
<p>DevOps is a <strong>cultural and technical movement</strong> that unifies software development (Dev) and IT operations (Ops). It aims to shorten the software development lifecycle, deliver high-quality software continuously, and create a feedback loop between development and production.</p>
<div class="pipeline-flow">
<div class="pipeline-stage" style="background: rgba(0,120,212,0.2); color: #0078D4;">Plan</div>
<span class="pipeline-arrow">β</span>
<div class="pipeline-stage" style="background: rgba(0,183,195,0.2); color: #00b7c3;">Code</div>
<span class="pipeline-arrow">β</span>
<div class="pipeline-stage" style="background: rgba(255,107,53,0.2); color: #ff6b35;">Build</div>
<span class="pipeline-arrow">β</span>
<div class="pipeline-stage" style="background: rgba(0,255,136,0.2); color: #00ff88;">Test</div>
<span class="pipeline-arrow">β</span>
<div class="pipeline-stage" style="background: rgba(163,113,247,0.2); color: #a371f7;">Release</div>
<span class="pipeline-arrow">β</span>
<div class="pipeline-stage" style="background: rgba(46,204,113,0.2); color: #2ecc71;">Deploy</div>
<span class="pipeline-arrow">β</span>
<div class="pipeline-stage" style="background: rgba(255,165,0,0.2); color: #ffa500;">Operate</div>
<span class="pipeline-arrow">β</span>
<div class="pipeline-stage" style="background: rgba(231,76,60,0.2); color: #e74c3c;">Monitor</div>
</div>
<h3>CI/CD β The Heart of DevOps</h3>
<table>
<tr><th>Concept</th><th>What It Does</th><th>Tools</th><th>Key Metric</th></tr>
<tr><td><strong>Continuous Integration (CI)</strong></td><td>Automatically build & test code on every commit</td><td>Azure Pipelines, Jenkins, GitHub Actions</td><td>Build success rate</td></tr>
<tr><td><strong>Continuous Delivery (CD)</strong></td><td>Automatically deploy to staging after tests pass</td><td>Azure Pipelines, ArgoCD, Spinnaker</td><td>Lead time for changes</td></tr>
<tr><td><strong>Continuous Deployment</strong></td><td>Auto-deploy to production (no manual gate)</td><td>Azure DevOps + approvals removed</td><td>Deployment frequency</td></tr>
<tr><td><strong>Continuous Testing (CT)</strong></td><td>Automated tests at every stage of the pipeline</td><td>Selenium, pytest, JUnit</td><td>Test pass rate</td></tr>
</table>
<h3>DevOps vs MLOps vs DataOps vs GitOps</h3>
<table>
<tr><th>Aspect</th><th>DevOps</th><th>MLOps</th><th>DataOps</th><th>GitOps</th></tr>
<tr><td>What ships?</td><td>Code β App</td><td>Code + Data + Model</td><td>Data pipelines</td><td>Declarative configs</td></tr>
<tr><td>Testing</td><td>Unit / Integration / E2E</td><td>+ Data & Model validation</td><td>Data quality checks</td><td>Policy checks</td></tr>
<tr><td>Versioning</td><td>Code (Git)</td><td>Code + Data + Model</td><td>Schema + Pipeline</td><td>Git as single source</td></tr>
<tr><td>Monitoring</td><td>Latency, Errors, CPU</td><td>+ Data/Model drift</td><td>Data freshness, quality</td><td>Drift detection</td></tr>
<tr><td>Trigger</td><td>Code push</td><td>Code push + Data change</td><td>Schedule + events</td><td>Git commit</td></tr>
</table>
<h3>DevOps Principles β CALMS Framework</h3>
<div class="info-box">
<div class="box-title">π― CALMS Framework</div>
<div class="box-content">
<strong>C</strong> β Culture: Break silos between Dev and Ops. Shared responsibility for production.<br>
<strong>A</strong> β Automation: Automate everything β builds, tests, deployments, infrastructure provisioning.<br>
<strong>L</strong> β Lean: Eliminate waste, small batch sizes. Inspired by Toyota Production System.<br>
<strong>M</strong> β Measurement: Measure everything using DORA metrics. Data-driven decisions.<br>
<strong>S</strong> β Sharing: Share knowledge, feedback loops, blameless postmortems.
</div>
</div>
<h3>The 12-Factor App Methodology</h3>
<p>A methodology for building modern, cloud-native, scalable applications β the foundation of DevOps-friendly software:</p>
<table>
<tr><th>#</th><th>Factor</th><th>Principle</th><th>DevOps Impact</th></tr>
<tr><td>1</td><td>Codebase</td><td>One codebase in version control</td><td>Single Git repo per service</td></tr>
<tr><td>2</td><td>Dependencies</td><td>Explicitly declare dependencies</td><td>pom.xml, requirements.txt, package.json</td></tr>
<tr><td>3</td><td>Config</td><td>Store config in environment variables</td><td>Azure Key Vault, ConfigMaps</td></tr>
<tr><td>4</td><td>Backing Services</td><td>Treat databases as attached resources</td><td>Connection strings via env vars</td></tr>
<tr><td>5</td><td>Build, Release, Run</td><td>Strict separation of stages</td><td>CI/CD pipeline stages</td></tr>
<tr><td>6</td><td>Processes</td><td>Stateless processes</td><td>Enables horizontal scaling</td></tr>
<tr><td>7</td><td>Port Binding</td><td>Export services via port binding</td><td>Containerized services</td></tr>
<tr><td>8</td><td>Concurrency</td><td>Scale via process model</td><td>K8s replica sets</td></tr>
<tr><td>9</td><td>Disposability</td><td>Fast startup, graceful shutdown</td><td>Health checks, readiness probes</td></tr>
<tr><td>10</td><td>Dev/Prod Parity</td><td>Keep environments similar</td><td>Docker + IaC ensures parity</td></tr>
<tr><td>11</td><td>Logs</td><td>Treat logs as event streams</td><td>Azure Monitor, Log Analytics</td></tr>
<tr><td>12</td><td>Admin Processes</td><td>Run admin tasks as one-off processes</td><td>K8s Jobs, Azure Functions</td></tr>
</table>
<h3>SRE vs DevOps β Key Differences</h3>
<table>
<tr><th>Aspect</th><th>DevOps</th><th>SRE (Site Reliability Engineering)</th></tr>
<tr><td>Origin</td><td>Industry movement</td><td>Google (2003)</td></tr>
<tr><td>Focus</td><td>Culture + Automation</td><td>Reliability + Engineering</td></tr>
<tr><td>Error Budget</td><td>Not formalized</td><td>Core concept: 100% - SLO = error budget</td></tr>
<tr><td>Toil</td><td>Reduce manual work</td><td>Max 50% toil, rest = engineering</td></tr>
<tr><td>On-Call</td><td>Varies</td><td>Structured rotation with blameless postmortems</td></tr>
<tr><td>Relationship</td><td colspan="2">SRE implements DevOps principles with concrete practices</td></tr>
</table>
<h3>DevSecOps β Shift-Left Security</h3>
<div class="callout warning">
<div class="callout-title">β οΈ Why DevSecOps Matters</div>
<strong>Cost of fixing vulnerabilities:</strong><br>
β’ Design phase: $1x<br>
β’ Development: $6.5x<br>
β’ Testing: $15x<br>
β’ Production: $100x<br><br>
DevSecOps integrates security at every stage, not as a final gate.
</div>
<div class="pipeline-flow">
<div class="pipeline-stage" style="background: rgba(231,76,60,0.2); color: #e74c3c;">Threat Model</div>
<span class="pipeline-arrow">β</span>
<div class="pipeline-stage" style="background: rgba(0,120,212,0.2); color: #0078D4;">SAST</div>
<span class="pipeline-arrow">β</span>
<div class="pipeline-stage" style="background: rgba(0,183,195,0.2); color: #00b7c3;">SCA</div>
<span class="pipeline-arrow">β</span>
<div class="pipeline-stage" style="background: rgba(255,107,53,0.2); color: #ff6b35;">Container Scan</div>
<span class="pipeline-arrow">β</span>
<div class="pipeline-stage" style="background: rgba(163,113,247,0.2); color: #a371f7;">DAST</div>
<span class="pipeline-arrow">β</span>
<div class="pipeline-stage" style="background: rgba(46,204,113,0.2); color: #2ecc71;">Runtime Protection</div>
</div>
<h3>Deployment Strategies Deep Dive</h3>
<table>
<tr><th>Strategy</th><th>How It Works</th><th>Downtime</th><th>Rollback</th><th>Risk</th><th>Best For</th></tr>
<tr><td><strong>Rolling Update</strong></td><td>Gradually replace old pods</td><td>Zero</td><td>Slow</td><td>Low</td><td>Standard deployments</td></tr>
<tr><td><strong>Blue-Green</strong></td><td>Two identical environments, switch traffic</td><td>Zero</td><td>Instant</td><td>Very Low</td><td>Mission-critical apps</td></tr>
<tr><td><strong>Canary</strong></td><td>Route small % to new version</td><td>Zero</td><td>Fast</td><td>Low</td><td>Feature validation</td></tr>
<tr><td><strong>A/B Testing</strong></td><td>Route by user segments</td><td>Zero</td><td>Fast</td><td>Low</td><td>UX experiments</td></tr>
<tr><td><strong>Shadow/Dark</strong></td><td>Mirror prod traffic to new version</td><td>Zero</td><td>N/A</td><td>Very Low</td><td>Performance testing</td></tr>
<tr><td><strong>Recreate</strong></td><td>Kill all old, create new</td><td>Yes</td><td>Slow</td><td>High</td><td>Dev/test only</td></tr>
</table>
`,
handson: `
<h3>DORA Metrics β Measuring DevOps Performance</h3>
<table>
<tr><th>Metric</th><th>Elite</th><th>High</th><th>Medium</th><th>Low</th></tr>
<tr><td>Deployment Frequency</td><td>Multiple/day</td><td>Weekly</td><td>Monthly</td><td>Months</td></tr>
<tr><td>Lead Time for Changes</td><td>< 1 hour</td><td>< 1 week</td><td>< 1 month</td><td>> 6 months</td></tr>
<tr><td>Change Failure Rate</td><td>0-15%</td><td>16-30%</td><td>16-30%</td><td>46-60%</td></tr>
<tr><td>Time to Restore</td><td>< 1 hour</td><td>< 1 day</td><td>< 1 week</td><td>> 6 months</td></tr>
</table>
<div class="callout insight">
<div class="callout-title">π‘ DORA + SPACE Framework</div>
Google's DORA metrics measure team delivery. GitHub's SPACE framework adds developer experience:<br>
<strong>S</strong>atisfaction, <strong>P</strong>erformance, <strong>A</strong>ctivity, <strong>C</strong>ommunication, <strong>E</strong>fficiency.<br>
Together, they provide a complete view of engineering productivity.
</div>
<h3>Shift-Left Testing</h3>
<p>Move testing earlier in the development lifecycle:</p>
<div class="code-block">
<span class="comment"># Traditional: Test late (expensive to fix)</span>
Code β Code β Code β <span class="keyword">TEST</span> β Fix β Fix β Deploy
<span class="comment"># Shift-Left: Test early (cheap to fix)</span>
Code β <span class="keyword">TEST</span> β Code β <span class="keyword">TEST</span> β Code β <span class="keyword">TEST</span> β Deploy
<span class="comment"># Test Pyramid (bottom = more, faster, cheaper)</span>
/ E2E \\ β Few, slow, expensive
/ Integration \\ β Moderate
/ Unit Tests \\ β Many, fast, cheap
/ Static Analysis \\ β Instant (linters, SAST)
</div>
<h3>Infrastructure as Code (IaC) β Terraform vs Bicep</h3>
<table>
<tr><th>Feature</th><th>Terraform</th><th>Bicep (Azure-native)</th><th>ARM Templates</th></tr>
<tr><td>Multi-cloud</td><td>β
Yes</td><td>β Azure only</td><td>β Azure only</td></tr>
<tr><td>State Management</td><td>Required (tfstate)</td><td>Not needed</td><td>Not needed</td></tr>
<tr><td>Readability</td><td>Good (HCL)</td><td>Excellent</td><td>Very verbose (JSON)</td></tr>
<tr><td>Learning Curve</td><td>Moderate</td><td>Low</td><td>High</td></tr>
<tr><td>Community</td><td>Very large</td><td>Growing</td><td>Legacy</td></tr>
</table>
<div class="code-block">
<span class="comment"># Terraform example β Azure Resource Group</span>
<span class="keyword">resource</span> <span class="string">"azurerm_resource_group"</span> <span class="string">"example"</span> {
<span class="key">name</span> = <span class="string">"rg-devops-prod"</span>
<span class="key">location</span> = <span class="string">"East US"</span>
<span class="key">tags</span> = {
<span class="key">environment</span> = <span class="string">"production"</span>
<span class="key">managed_by</span> = <span class="string">"terraform"</span>
}
}
<span class="comment"># Bicep equivalent β much cleaner!</span>
<span class="keyword">resource</span> rg <span class="string">'Microsoft.Resources/resourceGroups@2021-04-01'</span> = {
<span class="key">name</span>: <span class="string">'rg-devops-prod'</span>
<span class="key">location</span>: <span class="string">'eastus'</span>
<span class="key">tags</span>: {
<span class="key">environment</span>: <span class="string">'production'</span>
<span class="key">managed_by</span>: <span class="string">'bicep'</span>
}
}
</div>
<div class="callout insight">
<div class="callout-title">π‘ IaC Benefits</div>
<strong>Repeatability</strong> β Same infra every time<br>
<strong>Version Control</strong> β Track changes in Git<br>
<strong>Audit Trail</strong> β Who changed what and when<br>
<strong>Self-Documentation</strong> β Infra IS the documentation<br>
<strong>Blast Radius</strong> β Preview changes with <code>terraform plan</code> before applying
</div>
<h3>GitOps Workflow</h3>
<div class="code-block">
<span class="comment"># GitOps: Git is the single source of truth for infrastructure</span>
<span class="comment"># 1. Developer pushes change to Git</span>
<span class="keyword">git</span> commit -m <span class="string">"Update replicas to 5"</span>
<span class="keyword">git</span> push origin main
<span class="comment"># 2. GitOps operator (ArgoCD/Flux) detects change</span>
<span class="comment"># 3. Operator applies change to Kubernetes cluster</span>
<span class="comment"># 4. If cluster state drifts, operator auto-corrects</span>
<span class="comment"># ArgoCD Application Manifest</span>
<span class="key">apiVersion</span>: argoproj.io/v1alpha1
<span class="key">kind</span>: Application
<span class="key">metadata</span>:
<span class="key">name</span>: bankapp
<span class="key">spec</span>:
<span class="key">source</span>:
<span class="key">repoURL</span>: <span class="string">'https://dev.azure.com/org/project/_git/manifests'</span>
<span class="key">path</span>: <span class="string">'k8s/'</span>
<span class="key">destination</span>:
<span class="key">server</span>: <span class="string">'https://kubernetes.default.svc'</span>
<span class="key">namespace</span>: <span class="string">'production'</span>
<span class="key">syncPolicy</span>:
<span class="key">automated</span>:
<span class="key">prune</span>: true
<span class="key">selfHeal</span>: true
</div>
`,
applications: `
<h3>Real-World Applications</h3>
<div class="info-box">
<div class="box-title">π’ Industry Use Cases</div>
<div class="box-content">
<strong>Netflix:</strong> 1000+ deployments/day using CI/CD, canary releases, and Chaos Engineering<br>
<strong>Amazon:</strong> Deploys every 11.7 seconds on average. Microservices architecture since 2002.<br>
<strong>Google:</strong> Pioneered SRE. Manages billions of containers weekly with Borg/Kubernetes.<br>
<strong>Spotify:</strong> "Squad" model for autonomous DevOps teams. Each squad owns their full stack.<br>
<strong>Microsoft:</strong> Azure DevOps used internally for all products. 80,000+ engineers on one monorepo.<br>
<strong>Etsy:</strong> Pioneered continuous deployment in 2010. Deploys 50+ times/day.
</div>
</div>
<h3>Value Stream Mapping</h3>
<div class="info-box">
<div class="box-title">πΊοΈ Identify Bottlenecks in Your Delivery Pipeline</div>
<div class="box-content">
Value Stream Mapping (VSM) visualizes the flow of work from idea to production:<br><br>
<strong>Step 1:</strong> Map every step from idea β code β build β test β deploy β monitor<br>
<strong>Step 2:</strong> Measure lead time (total time) and process time (active work) for each step<br>
<strong>Step 3:</strong> Calculate % value-add vs wait time<br>
<strong>Step 4:</strong> Eliminate or automate non-value-add steps<br><br>
<strong>Typical finding:</strong> 80% of lead time is waiting (approvals, handoffs, queues). Only 20% is active work.
</div>
</div>
<div class="interview-box">
<div class="box-title">π Interview Questions & Answers</div>
<div class="box-content">
<strong>1. What is DevOps and why is it important?</strong><br>
DevOps unifies Dev and Ops to shorten delivery cycles, increase deployment frequency, and improve reliability. It's a cultural shift + automation practices. Key benefits: faster TTM, fewer failures, faster recovery.<br><br>
<strong>2. Explain CI vs CD (Delivery) vs CD (Deployment).</strong><br>
CI = auto build+test on every commit. Continuous Delivery = auto deploy to staging (manual prod gate). Continuous Deployment = auto deploy to production (no manual gate). Each builds on the previous.<br><br>
<strong>3. What are DORA metrics and why do they matter?</strong><br>
Four metrics from Google's research: Deployment Frequency, Lead Time for Changes, Change Failure Rate, Time to Restore. They correlate with organizational performance. Elite = multiple deploys/day, <1hr lead time.<br><br>
<strong>4. How does DevOps differ from MLOps?</strong><br>
MLOps adds data versioning, model versioning, experiment tracking, data drift detection, and continuous training. ML has more axes of change β code, data, model, hyperparameters β making it more complex.<br><br>
<strong>5. What is Shift-Left testing?</strong><br>
Move testing earlier in the lifecycle. Includes static analysis in IDE, pre-commit hooks, CI-level unit tests, and security scanning before deployment. Catches bugs when they're cheapest to fix.<br><br>
<strong>6. Explain Infrastructure as Code (IaC) and its benefits.</strong><br>
Define infrastructure in code files (Terraform, Bicep, ARM). Benefits: repeatability, version control, peer review, audit trail, self-documentation. Enables GitOps where Git is the source of truth.<br><br>
<strong>7. What is the CALMS framework?</strong><br>
Culture (break silos), Automation (CI/CD, IaC), Lean (small batches), Measurement (DORA metrics), Sharing (knowledge, postmortems). It's a maturity model for assessing DevOps adoption.<br><br>
<strong>8. Explain Blue-Green vs Canary deployments.</strong><br>
Blue-Green: two identical environments, switch 100% traffic at once. Instant rollback by switching back. Canary: gradually increase traffic (1% β 5% β 25% β 100%). Lower risk but slower rollout.<br><br>
<strong>9. What is GitOps?</strong><br>
Git as the single source of truth for infrastructure. An operator (ArgoCD/Flux) watches Git repos and auto-applies changes to clusters. If cluster drifts, operator auto-corrects. Declarative, auditable, reversible.<br><br>
<strong>10. What is the 12-Factor App methodology?</strong><br>
12 principles for building cloud-native apps: single codebase, explicit dependencies, config in env vars, backing services as resources, strict build/release/run stages, stateless processes, port binding, concurrency, disposability, dev/prod parity, logs as streams, admin tasks as one-off processes.<br><br>
<strong>11. What is SRE and how does it relate to DevOps?</strong><br>
SRE (Site Reliability Engineering) is Google's implementation of DevOps principles. Key concepts: SLOs (reliability targets), error budgets (100% - SLO = room for innovation), toil reduction (max 50%), blameless postmortems.<br><br>
<strong>12. What is DevSecOps?</strong><br>
Integrating security at every stage of the DevOps pipeline: threat modeling in design, SAST in CI, SCA for dependencies, container scanning, DAST in staging, runtime protection in production. "Security is everyone's responsibility."<br><br>
<strong>13. How do you measure DevOps maturity?</strong><br>
Use DORA metrics as baseline. Assess: automation level (manual β partial β full), deployment frequency, test coverage, IaC adoption, monitoring coverage, incident response time, cultural adoption (blameless postmortems, shared ownership).<br><br>
<strong>14. What is Value Stream Mapping?</strong><br>
VSM visualizes the flow from idea to production, measuring lead time vs process time at each step. Typically reveals 80% of lead time is waiting (approvals, handoffs). Used to identify and eliminate bottlenecks.<br><br>
<strong>15. Explain the concept of "Toil" in SRE.</strong><br>
Toil is manual, repetitive, automatable operational work that scales linearly with service size. Google mandates no more than 50% toil β the rest should be engineering work to eliminate toil. Examples: manual deployments, alert handling, capacity planning.
</div>
</div>
`
},
"azure-setup": {
concepts: `
<h3>Azure DevOps β The Complete Platform</h3>
<p>Azure DevOps is Microsoft's end-to-end DevOps platform. It provides 5 integrated services that cover the entire software development lifecycle.</p>
<table>
<tr><th>Service</th><th>Purpose</th><th>Equivalent</th><th>Key Features</th></tr>
<tr><td><strong>Azure Boards</strong></td><td>Work tracking, Kanban, Sprints</td><td>Jira, Trello</td><td>Epics, Features, Stories, Bugs, Sprints, Burndown charts</td></tr>
<tr><td><strong>Azure Repos</strong></td><td>Git repositories</td><td>GitHub, GitLab</td><td>Branch policies, PR reviews, TFVC support</td></tr>
<tr><td><strong>Azure Pipelines</strong></td><td>CI/CD automation</td><td>Jenkins, GitHub Actions</td><td>YAML + Classic, multi-stage, 1800+ tasks</td></tr>
<tr><td><strong>Azure Test Plans</strong></td><td>Manual & automated testing</td><td>TestRail</td><td>Test suites, exploratory testing, traceability</td></tr>
<tr><td><strong>Azure Artifacts</strong></td><td>Package management</td><td>Nexus, JFrog</td><td>npm, Maven, NuGet, Python, Universal packages</td></tr>
</table>
<h3>Project Hierarchy & Governance</h3>
<div class="info-box">
<div class="box-title">π Azure DevOps Hierarchy</div>
<div class="box-content">
<strong>Organization</strong> (top level β company or business unit)<br>
βββ <strong>Project 1</strong> (team/product β e.g., "Multi-Tier Application")<br>
β βββ <strong>Repos</strong> (multiple repos per project)<br>
β βββ <strong>Pipelines</strong> (CI/CD definitions)<br>
β βββ <strong>Boards</strong> (work items, sprints, Kanban)<br>
β βββ <strong>Test Plans</strong> (test suites)<br>
β βββ <strong>Artifacts</strong> (packages)<br>
βββ <strong>Project 2</strong> (another team/product)
</div>
</div>
<h3>Setting Up Azure DevOps</h3>
<div class="info-box">
<div class="box-title">π Setup Flow</div>
<div class="box-content">
<strong>Step 1:</strong> Go to portal.azure.com β Search "Azure DevOps Organization"<br>
<strong>Step 2:</strong> Click "Create new Organization" β Name it (e.g., "myorgforyaml")<br>
<strong>Step 3:</strong> Create a Project (e.g., "Multi-Tier Application")<br>
<strong>Step 4:</strong> Set visibility (Private recommended for enterprise)<br>
<strong>Step 5:</strong> Azure Repos is automatically created with the project<br>
<strong>Step 6:</strong> Configure process template (Agile, Scrum, or CMMI)
</div>
</div>
<h3>Process Templates β Agile vs Scrum vs CMMI</h3>
<table>
<tr><th>Template</th><th>Work Item Types</th><th>Best For</th><th>Key Difference</th></tr>
<tr><td><strong>Agile</strong></td><td>Epic β Feature β User Story β Task</td><td>Most teams</td><td>Flexible, user story focused</td></tr>
<tr><td><strong>Scrum</strong></td><td>Epic β Feature β PBI β Task</td><td>Scrum teams</td><td>Sprint-focused with burndown</td></tr>
<tr><td><strong>CMMI</strong></td><td>Epic β Feature β Requirement β Task</td><td>Regulated industries</td><td>Formal change management</td></tr>
<tr><td><strong>Basic</strong></td><td>Epic β Issue β Task</td><td>Simple projects</td><td>Minimal overhead</td></tr>
</table>
<h3>Branching Strategies</h3>
<table>
<tr><th>Strategy</th><th>Best For</th><th>Branches</th><th>Release Cadence</th></tr>
<tr><td><strong>Trunk-Based</strong></td><td>Small teams, fast releases</td><td>main + short-lived feature branches</td><td>Multiple/day</td></tr>
<tr><td><strong>GitFlow</strong></td><td>Scheduled releases</td><td>main, develop, feature/*, release/*, hotfix/*</td><td>Weekly/Monthly</td></tr>
<tr><td><strong>GitHub Flow</strong></td><td>Continuous deployment</td><td>main + feature branches + PRs</td><td>Multiple/day</td></tr>
<tr><td><strong>Release Flow</strong></td><td>Large teams (Microsoft uses this)</td><td>main + topic branches + release/*</td><td>Scheduled sprints</td></tr>
</table>
<div class="callout insight">
<div class="callout-title">π‘ Microsoft's Recommendation</div>
For most teams, <strong>Trunk-Based Development</strong> with short-lived feature branches is the best strategy. It reduces merge conflicts, enables CI, and aligns with DORA's findings that trunk-based development correlates with elite performance.
</div>
<h3>Azure DevOps CLI & REST API</h3>
<div class="info-box">
<div class="box-title">π§ Automation Beyond the UI</div>
<div class="box-content">
<strong>Azure DevOps CLI:</strong> <code>az devops</code> extension for managing projects, repos, pipelines from terminal<br>
<strong>REST API:</strong> Full programmatic access to all Azure DevOps services<br>
<strong>Service Hooks:</strong> Webhooks to integrate with Slack, Teams, Jenkins, etc.<br>
<strong>Azure DevOps Extensions:</strong> 1000+ marketplace extensions for custom functionality
</div>
</div>
`,
handson: `
<h3>Uploading Code to Azure Repos</h3>
<div class="code-block">
<span class="comment"># Step 1: Initialize local repo</span>
<span class="keyword">git</span> init
<span class="comment"># Step 2: Stage all files</span>
<span class="keyword">git</span> add .
<span class="comment"># Step 3: Commit</span>
<span class="keyword">git</span> commit -m <span class="string">"Initial commit"</span>
<span class="comment"># Step 4: Switch to main branch</span>
<span class="keyword">git</span> branch -M main
<span class="comment"># Step 5: Add Azure remote and push</span>
<span class="keyword">git</span> remote add origin https://myorg@dev.azure.com/myorg/Project/_git/Project
<span class="keyword">git</span> push -u origin --all
</div>
<h3>Branch Policies (Best Practice)</h3>
<div class="code-block">
<span class="comment"># Recommended branch policies for 'main':</span>
β
Require pull request reviews (min 1 reviewer)
β
Check for linked work items
β
Build validation (CI must pass)
β
Comment resolution required
β
Limit merge types (squash merge preferred)
β
Automatic reviewers for critical paths
β
Status checks (SonarQube quality gate)
</div>
<h3>Azure DevOps CLI</h3>
<div class="code-block">
<span class="comment"># Install Azure DevOps CLI extension</span>
<span class="keyword">az</span> extension add --name azure-devops
<span class="comment"># Configure default organization and project</span>
<span class="keyword">az</span> devops configure --defaults organization=https://dev.azure.com/myorg project=MyProject
<span class="comment"># Create a new project</span>
<span class="keyword">az</span> devops project create --name <span class="string">"NewProject"</span> --visibility private
<span class="comment"># List all repos in a project</span>
<span class="keyword">az</span> repos list --output table
<span class="comment"># Create a pull request</span>
<span class="keyword">az</span> repos pr create \\
--repository MyRepo \\
--source-branch feature/new-feature \\
--target-branch main \\
--title <span class="string">"Add new feature"</span> \\
--description <span class="string">"Implements user authentication"</span>
<span class="comment"># List pipelines</span>
<span class="keyword">az</span> pipelines list --output table
<span class="comment"># Run a pipeline</span>
<span class="keyword">az</span> pipelines run --name <span class="string">"CI-Pipeline"</span> --branch main
</div>
<h3>REST API Examples</h3>
<div class="code-block">
<span class="comment"># List all projects in an organization</span>
<span class="keyword">curl</span> -u :$(PAT) \\
<span class="string">"https://dev.azure.com/{org}/_apis/projects?api-version=7.0"</span>
<span class="comment"># Queue a pipeline run via REST API</span>
<span class="keyword">curl</span> -X POST \\
-u :$(PAT) \\
-H <span class="string">"Content-Type: application/json"</span> \\
-d <span class="string">'{"definition":{"id":1},"sourceBranch":"refs/heads/main"}'</span> \\
<span class="string">"https://dev.azure.com/{org}/{project}/_apis/build/builds?api-version=7.0"</span>
<span class="comment"># Create a work item</span>
<span class="keyword">curl</span> -X POST \\
-u :$(PAT) \\
-H <span class="string">"Content-Type: application/json-patch+json"</span> \\
-d <span class="string">'[{"op":"add","path":"/fields/System.Title","value":"New Bug"}]'</span> \\
<span class="string">"https://dev.azure.com/{org}/{project}/_apis/wit/workitems/$Bug?api-version=7.0"</span>
</div>
<h3>Azure Boards β Agile Configuration</h3>
<div class="info-box">
<div class="box-title">π Sprint Setup Checklist</div>
<div class="box-content">
<strong>1.</strong> Define iteration paths (Sprint 1, Sprint 2, etc.)<br>
<strong>2.</strong> Set sprint dates and capacity for each team member<br>
<strong>3.</strong> Create backlog items (User Stories / PBIs)<br>
<strong>4.</strong> Break stories into tasks with estimates<br>
<strong>5.</strong> Use Kanban board for daily standups<br>
<strong>6.</strong> Track burndown chart for sprint health<br>
<strong>7.</strong> Link work items to commits and PRs for traceability
</div>
</div>
`,
applications: `
<h3>Azure DevOps vs GitHub β Decision Matrix</h3>
<table>
<tr><th>Feature</th><th>Azure DevOps</th><th>GitHub</th><th>Winner</th></tr>
<tr><td>CI/CD</td><td>Azure Pipelines (YAML + Classic)</td><td>GitHub Actions</td><td>Azure (more mature)</td></tr>
<tr><td>Work Tracking</td><td>Azure Boards (enterprise-grade)</td><td>GitHub Issues + Projects</td><td>Azure (enterprise)</td></tr>
<tr><td>Packages</td><td>Azure Artifacts (npm, Maven, NuGet, Python)</td><td>GitHub Packages</td><td>Tie</td></tr>
<tr><td>Security</td><td>Advanced Security, RBAC</td><td>Dependabot, Code Scanning</td><td>GitHub (Copilot)</td></tr>
<tr><td>Community</td><td>Enterprise-focused</td><td>Largest open-source community</td><td>GitHub</td></tr>
<tr><td>Best For</td><td>Enterprise, Azure-heavy orgs</td><td>Open source, startups</td><td>Depends on context</td></tr>
</table>
<h3>Enterprise Governance Patterns</h3>
<div class="info-box">
<div class="box-title">π’ Multi-Team Organization</div>
<div class="box-content">
<strong>Pattern 1: One Project per Team</strong> β Full isolation, separate backlogs. Best for independent teams.<br>
<strong>Pattern 2: One Project, Multiple Repos</strong> β Shared boards, separate code. Best for related services.<br>
<strong>Pattern 3: Monorepo</strong> β All code in one repo with path-based pipelines. Best for tight coupling.<br><br>
<strong>Microsoft's recommendation:</strong> Start with fewer projects. Use area paths and teams within a project for organization. Only split projects when teams need true independence.
</div>
</div>
<div class="interview-box">
<div class="box-title">π Interview Questions & Answers</div>
<div class="box-content">
<strong>1. What are the 5 main services in Azure DevOps?</strong><br>
Azure Boards (work tracking), Azure Repos (Git), Azure Pipelines (CI/CD), Azure Test Plans (testing), Azure Artifacts (packages). Each can be used independently or together.<br><br>
<strong>2. How do you set up an Azure DevOps Organization?</strong><br>
Go to dev.azure.com β Create organization β Create project β Choose process template (Agile/Scrum/CMMI) β Set visibility. Each org gets 1 free parallel job + 1800 CI/CD minutes/month.<br><br>
<strong>3. Azure Repos vs GitHub β when to use which?</strong><br>
Azure Repos for enterprise teams heavily invested in Azure, needing Azure Boards integration. GitHub for open-source, community, GitHub Copilot, and when using GitHub Actions. Many large orgs use both.<br><br>
<strong>4. Explain Trunk-Based vs GitFlow.</strong><br>
Trunk-Based: short-lived branches merged to main frequently. Fast CI, less merge conflicts. GitFlow: long-lived develop branch, release branches. Better for scheduled releases. DORA research shows trunk-based correlates with higher performance.<br><br>
<strong>5. What are Branch Policies?</strong><br>
Rules enforced on branches: required reviewers, build validation, linked work items, comment resolution, merge type restrictions. They prevent direct pushes and ensure code quality on protected branches.<br><br>
<strong>6. How do you push code to Azure Repos using Git CLI?</strong><br>
git init β git add . β git commit β git branch -M main β git remote add origin [Azure URL] β git push -u origin --all. Authenticate with PAT or SSH key.<br><br>
<strong>7. What is a PAT and when is it needed?</strong><br>
Personal Access Token β an alternative to passwords for Azure DevOps authentication. Used for Git operations, REST API calls, and CI/CD. Should have minimum scopes and short expiration. Prefer Managed Identity when possible.<br><br>
<strong>8. What Azure DevOps process templates are available?</strong><br>
Agile (User Stories), Scrum (PBIs), CMMI (Requirements β for regulated industries), Basic (simple Issues). Each defines different work item types, workflows, and board layouts.<br><br>
<strong>9. How do you automate Azure DevOps with CLI?</strong><br>
Install az devops extension. Configure defaults with az devops configure. Then use az repos, az pipelines, az boards commands for creating PRs, running pipelines, managing work items programmatically.<br><br>
<strong>10. Explain Azure DevOps REST API use cases.</strong><br>
Programmatic access to all services: queue builds, create work items, manage repos, query analytics. Useful for custom dashboards, cross-tool integration, automated governance, and audit reporting.<br><br>
<strong>11. How do you manage access control in Azure DevOps?</strong><br>
Three levels: Organization (security groups), Project (teams + groups), Repository (branch policies). Built-in groups: Project Admins, Contributors, Readers. Support Azure AD integration for SSO and conditional access.<br><br>
<strong>12. What is Azure Artifacts and when would you use it?</strong><br>
Private package registry supporting npm, Maven, NuGet, Python, Universal packages. Use when: sharing libraries across teams, caching upstream packages (proxy), ensuring reproducible builds, managing internal dependencies.
</div>
</div>
`
},
"infrastructure": {
concepts: `
<h3>Azure Networking for DevOps</h3>
<p>Before deploying applications, you need a <strong>secure network environment</strong>. The project sets up isolated networking so no outside entity can access resources directly.</p>
<table>
<tr><th>Component</th><th>Purpose</th><th>Azure Equivalent</th><th>AWS Equivalent</th></tr>
<tr><td><strong>VPC / VNet</strong></td><td>Isolated virtual network</td><td>Azure Virtual Network</td><td>AWS VPC</td></tr>
<tr><td><strong>Subnet</strong></td><td>Segment within a VNet</td><td>Subnet</td><td>Subnet</td></tr>
<tr><td><strong>Security Group</strong></td><td>Firewall rules for VMs</td><td>Network Security Group (NSG)</td><td>Security Group</td></tr>
<tr><td><strong>NAT Gateway</strong></td><td>Outbound internet for private subnets</td><td>Azure NAT Gateway</td><td>NAT Gateway</td></tr>
<tr><td><strong>Load Balancer</strong></td><td>Distribute traffic across VMs</td><td>Azure Load Balancer / App Gateway</td><td>ALB / NLB</td></tr>
<tr><td><strong>Private Link</strong></td><td>Private access to PaaS services</td><td>Azure Private Endpoint</td><td>AWS PrivateLink</td></tr>
<tr><td><strong>DNS</strong></td><td>Name resolution</td><td>Azure DNS / Private DNS Zone</td><td>Route 53</td></tr>
</table>
<h3>Azure Landing Zones</h3>
<div class="info-box">
<div class="box-title">ποΈ Enterprise-Scale Architecture</div>
<div class="box-content">
Azure Landing Zones are a set of reference architectures for setting up multi-subscription Azure environments:<br><br>
<strong>Management Group:</strong> Top-level governance container<br>
βββ <strong>Platform</strong> (shared services: identity, management, connectivity)<br>
β βββ Identity (Azure AD, DNS)<br>
β βββ Management (monitoring, automation)<br>
β βββ Connectivity (hub VNet, firewall, VPN)<br>
βββ <strong>Landing Zones</strong> (workload subscriptions)<br>
βββ Corp (internal apps β private connectivity)<br>
βββ Online (public-facing apps β internet connectivity)
</div>
</div>
<h3>Hub-and-Spoke Network Topology</h3>
<div class="info-box">
<div class="box-title">π Recommended Enterprise Pattern</div>
<div class="box-content">
<strong>Hub VNet:</strong> Shared services β Azure Firewall, VPN Gateway, Bastion, DNS<br>
<strong>Spoke VNet (Dev):</strong> Development workloads β VNet peered to Hub<br>
<strong>Spoke VNet (Staging):</strong> Pre-production β VNet peered to Hub<br>
<strong>Spoke VNet (Prod):</strong> Production workloads β VNet peered to Hub<br><br>
All traffic flows through the Hub's firewall for centralized security and logging.
</div>
</div>
<h3>NSG vs Azure Firewall vs WAF</h3>
<table>
<tr><th>Feature</th><th>NSG</th><th>Azure Firewall</th><th>WAF (Web Application Firewall)</th></tr>
<tr><td>Layer</td><td>L3/L4 (Network)</td><td>L3-L7 (Network + App)</td><td>L7 (Application only)</td></tr>
<tr><td>Scope</td><td>Subnet / NIC level</td><td>VNet level</td><td>Per App Gateway / Front Door</td></tr>
<tr><td>Use Case</td><td>Basic port filtering</td><td>Centralized egress control, FQDN filtering</td><td>OWASP protection, SQL injection, XSS</td></tr>
<tr><td>Cost</td><td>Free</td><td>~$900/month</td><td>~$200/month per gateway</td></tr>
<tr><td>Logging</td><td>NSG Flow Logs</td><td>Full IDPS, threat intelligence</td><td>WAF logs with rule matches</td></tr>
</table>
<h3>VM Roles in the Pipeline</h3>
<div class="info-box">
<div class="box-title">π₯οΈ VM Roles</div>
<div class="box-content">
<strong>Agent VM:</strong> Runs the Azure Pipelines self-hosted agent. Has Maven, Java, Docker, Trivy, kubectl installed.<br>
<strong>SonarQube VM:</strong> Hosts Docker + SonarQube container for code quality analysis.<br>
Both VMs are placed in security groups with controlled inbound rules.
</div>
</div>
<h3>Security Group Rules</h3>
<table>
<tr><th>Port</th><th>Protocol</th><th>Purpose</th><th>Best Practice</th></tr>
<tr><td>22</td><td>SSH</td><td>Remote access to VMs</td><td>Restrict to your IP or use Bastion</td></tr>
<tr><td>80/443</td><td>HTTP/HTTPS</td><td>Web traffic</td><td>Use only HTTPS in production</td></tr>
<tr><td>9000</td><td>TCP</td><td>SonarQube dashboard</td><td>Internal only or VPN</td></tr>
<tr><td>30000-32767</td><td>TCP</td><td>Kubernetes NodePort range</td><td>Use LoadBalancer/Ingress instead</td></tr>
<tr><td>465</td><td>SMTPS</td><td>Email notifications</td><td>Use managed email service</td></tr>
</table>
<div class="callout warning">
<div class="callout-title">β οΈ Security Best Practices</div>
Never use "0.0.0.0/0" (open to all) in production. Restrict SSH access to your IP range. Use Azure Bastion for secure VM access instead of public IPs. Enable NSG flow logs for auditing. Use Private Endpoints for PaaS services.
</div>
`,
handson: `
<h3>Creating Azure VNet with CLI</h3>
<div class="code-block">
<span class="comment"># Create a resource group</span>
<span class="keyword">az</span> group create --name rg-devops --location eastus
<span class="comment"># Create a VNet with subnet</span>
<span class="keyword">az</span> network vnet create \\
--resource-group rg-devops \\
--name vnet-devops \\
--address-prefix <span class="string">10.0.0.0/16</span> \\
--subnet-name subnet-agents \\
--subnet-prefix <span class="string">10.0.1.0/24</span>
<span class="comment"># Create NSG with rules</span>
<span class="keyword">az</span> network nsg create --resource-group rg-devops --name nsg-agents
<span class="keyword">az</span> network nsg rule create \\
--resource-group rg-devops \\
--nsg-name nsg-agents \\
--name AllowSSH \\
--priority 100 \\
--destination-port-ranges 22 \\
--access Allow \\
--protocol Tcp \\
--source-address-prefixes <span class="string">"YOUR_IP/32"</span>
</div>
<h3>Terraform for Azure Infrastructure</h3>
<div class="code-block">
<span class="comment"># main.tf β Azure VNet + Subnet + NSG</span>
<span class="keyword">terraform</span> {
<span class="key">required_providers</span> {
<span class="key">azurerm</span> = {
<span class="key">source</span> = <span class="string">"hashicorp/azurerm"</span>
<span class="key">version</span> = <span class="string">"~> 3.0"</span>
}
}
<span class="key">backend</span> <span class="string">"azurerm"</span> {
<span class="key">resource_group_name</span> = <span class="string">"rg-terraform-state"</span>
<span class="key">storage_account_name</span> = <span class="string">"tfstatedevops"</span>
<span class="key">container_name</span> = <span class="string">"tfstate"</span>
<span class="key">key</span> = <span class="string">"terraform.tfstate"</span>
}
}
<span class="keyword">resource</span> <span class="string">"azurerm_virtual_network"</span> <span class="string">"devops"</span> {
<span class="key">name</span> = <span class="string">"vnet-devops"</span>
<span class="key">address_space</span> = [<span class="string">"10.0.0.0/16"</span>]
<span class="key">location</span> = azurerm_resource_group.devops.location
<span class="key">resource_group_name</span> = azurerm_resource_group.devops.name
}
<span class="keyword">resource</span> <span class="string">"azurerm_subnet"</span> <span class="string">"agents"</span> {
<span class="key">name</span> = <span class="string">"subnet-agents"</span>
<span class="key">virtual_network_name</span> = azurerm_virtual_network.devops.name
<span class="key">address_prefixes</span> = [<span class="string">"10.0.1.0/24"</span>]
}
</div>
<h3>Bicep Template β Complete Network Setup</h3>
<div class="code-block">
<span class="comment">// network.bicep β Hub Network with Firewall</span>
<span class="keyword">param</span> location <span class="keyword">string</span> = resourceGroup().location
<span class="keyword">resource</span> hubVnet <span class="string">'Microsoft.Network/virtualNetworks@2023-04-01'</span> = {
<span class="key">name</span>: <span class="string">'vnet-hub'</span>
<span class="key">location</span>: location
<span class="key">properties</span>: {
<span class="key">addressSpace</span>: { <span class="key">addressPrefixes</span>: [<span class="string">'10.0.0.0/16'</span>] }
<span class="key">subnets</span>: [
{
<span class="key">name</span>: <span class="string">'AzureFirewallSubnet'</span>
<span class="key">properties</span>: { <span class="key">addressPrefix</span>: <span class="string">'10.0.1.0/24'</span> }
}
{
<span class="key">name</span>: <span class="string">'AzureBastionSubnet'</span>
<span class="key">properties</span>: { <span class="key">addressPrefix</span>: <span class="string">'10.0.2.0/24'</span> }
}
]
}
}
<span class="keyword">resource</span> spokeVnet <span class="string">'Microsoft.Network/virtualNetworks@2023-04-01'</span> = {
<span class="key">name</span>: <span class="string">'vnet-spoke-prod'</span>
<span class="key">location</span>: location
<span class="key">properties</span>: {
<span class="key">addressSpace</span>: { <span class="key">addressPrefixes</span>: [<span class="string">'10.1.0.0/16'</span>] }
}
}
</div>
<h3>Self-Hosted Agent Setup</h3>
<div class="code-block">
<span class="comment"># Install self-hosted agent on Ubuntu VM</span>
<span class="comment"># 1. Download agent</span>
<span class="keyword">mkdir</span> myagent && <span class="keyword">cd</span> myagent
<span class="keyword">wget</span> https://vstsagentpackage.azureedge.net/.../vsts-agent-linux-x64.tar.gz
<span class="keyword">tar</span> zxvf vsts-agent-linux-x64.tar.gz
<span class="comment"># 2. Configure agent</span>
./config.sh \\
--url https://dev.azure.com/myorg \\
--auth pat \\
--token <span class="string">YOUR_PAT</span> \\
--pool <span class="string">"myagentpool"</span> \\
--agent <span class="string">"agent-vm-01"</span>
<span class="comment"># 3. Install as service and start</span>
<span class="keyword">sudo</span> ./svc.sh install
<span class="keyword">sudo</span> ./svc.sh start
<span class="comment"># 4. Install required tools</span>
<span class="keyword">sudo</span> apt-get install -y maven openjdk-17-jdk docker.io
<span class="keyword">curl</span> -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh
</div>
`,
applications: `
<h3>Network Architecture Patterns</h3>
<div class="info-box">
<div class="box-title">ποΈ Production Network Checklist</div>
<div class="box-content">
β
<strong>Hub-Spoke topology</strong> with centralized firewall<br>
β
<strong>Azure Bastion</strong> for secure VM access (no public IPs)<br>
β
<strong>Private Endpoints</strong> for all PaaS services (ACR, Key Vault, SQL)<br>
β
<strong>NSG Flow Logs</strong> enabled for audit and troubleshooting<br>
β
<strong>Azure DDoS Protection</strong> on public-facing VNets<br>
β
<strong>Network Watcher</strong> for diagnostics and topology visualization<br>
β
<strong>Service Endpoints</strong> or Private Links for Azure-to-Azure traffic<br>
β
<strong>DNS Zones</strong> for internal name resolution
</div>
</div>
<h3>Cost Optimization</h3>
<table>
<tr><th>Resource</th><th>Cost Tip</th><th>Savings</th></tr>
<tr><td>VMs</td><td>Use B-series (burstable) for dev/test agents</td><td>~60%</td></tr>
<tr><td>Bastion</td><td>Use Basic SKU or stop when not needed</td><td>~50%</td></tr>
<tr><td>Firewall</td><td>Use Firewall Basic SKU for small workloads</td><td>~50%</td></tr>
<tr><td>NAT Gateway</td><td>Share across subnets in same VNet</td><td>~30%</td></tr>
<tr><td>VPN Gateway</td><td>Use P2S instead of S2S for dev teams</td><td>~40%</td></tr>
</table>
<div class="interview-box">
<div class="box-title">π Interview Questions & Answers</div>
<div class="box-content">
<strong>1. What is an Azure VNet and why is it needed?</strong><br>
A VNet is an isolated virtual network in Azure. It provides: network segmentation, security boundaries (NSGs), connectivity to on-premises (VPN/ExpressRoute), and private access to Azure services. Every Azure resource needs a network context.<br><br>
<strong>2. NSG vs Azure Firewall β when to use which?</strong><br>
NSG: basic L3/L4 filtering at subnet/NIC level, free. Azure Firewall: centralized L3-L7 filtering, FQDN filtering, threat intelligence, IDPS. Use NSG for simple rules, Firewall for centralized egress control and compliance.<br><br>
<strong>3. What ports does a Kubernetes cluster need?</strong><br>
API Server: 443 (HTTPS). kubelet: 10250. NodePort range: 30000-32767. etcd: 2379-2380. Required for pod-to-pod communication, service discovery, and external access.<br><br>
<strong>4. How do you secure SSH access to Azure VMs?</strong><br>
Best: Use Azure Bastion (no public IP needed). Good: Restrict NSG to your IP range. Also: use SSH keys instead of passwords, enable Just-In-Time VM access, use Azure AD SSH login.<br><br>
<strong>5. What is Hub-and-Spoke architecture?</strong><br>
Hub VNet has shared services (firewall, VPN, Bastion). Spoke VNets have workloads (dev, staging, prod). Connected via VNet Peering. All traffic routes through hub firewall. Recommended by Microsoft for enterprise.<br><br>
<strong>6. What are Azure Private Endpoints?</strong><br>
Private Endpoints give PaaS services (ACR, Key Vault, SQL) a private IP in your VNet. Traffic stays on Microsoft backbone, never goes to public internet. Essential for security compliance.<br><br>
<strong>7. How do you set up a self-hosted pipeline agent?</strong><br>
Create a VM in your VNet. Download the Azure Pipelines agent package. Configure with your org URL and PAT. Install as a Linux service. Add to an agent pool. Install required tools (Docker, Maven, etc.).<br><br>
<strong>8. What are Azure Landing Zones?</strong><br>
Reference architecture for multi-subscription environments. Includes: management groups for governance, platform subscriptions (identity, management, connectivity), and landing zone subscriptions for workloads. Follows Azure Cloud Adoption Framework.<br><br>
<strong>9. Terraform vs Bicep β which to choose?</strong><br>
Terraform: multi-cloud, large ecosystem, requires state management. Bicep: Azure-native, no state needed, cleaner syntax than ARM. Use Terraform for multi-cloud. Use Bicep for Azure-only with simpler toolchain.<br><br>
<strong>10. How would you design a network for a multi-tier application?</strong><br>
Hub-Spoke with separate subnets per tier: Web tier (public subnet with WAF/App Gateway), App tier (private subnet), Data tier (private with Private Endpoints). NSGs between tiers. All egress through Azure Firewall in hub. Azure Bastion for management access.
</div>
</div>
`
},
"cicd-yaml": {
concepts: `
<h3>YAML Pipeline β Core Components</h3>
<p>Azure DevOps YAML pipelines are <strong>pipeline-as-code</strong> β giving you version control, code review, and full traceability. The YAML file lives in your repo alongside your source code.</p>
<table>
<tr><th>Component</th><th>Purpose</th><th>Scope</th><th>Example</th></tr>
<tr><td><strong>Trigger</strong></td><td>What starts the pipeline</td><td>Branch, PR, Schedule, None</td><td><code>trigger: [main]</code></td></tr>
<tr><td><strong>Pool</strong></td><td>Where it runs</td><td>MS-hosted or Self-hosted</td><td><code>pool: {name: 'mypool'}</code></td></tr>
<tr><td><strong>Variables</strong></td><td>Reusable values</td><td>Pipeline, Stage, Job</td><td><code>variables: {tag: 'v1'}</code></td></tr>
<tr><td><strong>Stages</strong></td><td>Logical groups (Build, Test, Deploy)</td><td>Sequential or parallel</td><td><code>stages: [{stage: Build}]</code></td></tr>
<tr><td><strong>Jobs</strong></td><td>Units of work within a stage</td><td>Run on an agent</td><td><code>jobs: [{job: compile}]</code></td></tr>
<tr><td><strong>Steps</strong></td><td>Individual tasks</td><td>Script, Task, Checkout</td><td><code>steps: [{script: 'echo hi'}]</code></td></tr>
</table>
<h3>Pipeline Hierarchy</h3>
<div class="info-box">
<div class="box-title">π Structure (Top β Bottom)</div>
<div class="box-content">
<strong>Pipeline</strong><br>
βββ trigger / pr / schedules<br>
βββ variables / parameters<br>
βββ resources (repos, pipelines, containers)<br>
βββ <strong>stages[]</strong><br>
βββ condition / dependsOn<br>
βββ <strong>jobs[]</strong> (or deployment jobs)<br>
βββ pool / environment<br>
βββ strategy (runOnce, rolling, canary)<br>
βββ <strong>steps[]</strong><br>
βββ checkout / script / task / template
</div>
</div>
<h3>Trigger Types</h3>
<table>
<tr><th>Type</th><th>When It Fires</th><th>YAML</th><th>Use Case</th></tr>
<tr><td>CI Trigger</td><td>Push to branch</td><td><code>trigger: [main]</code></td><td>Main pipeline</td></tr>
<tr><td>PR Trigger</td><td>PR created</td><td><code>pr: [main]</code></td><td>Validation builds</td></tr>
<tr><td>Scheduled</td><td>Cron schedule</td><td><code>schedules: [{cron: ...}]</code></td><td>Nightly builds, drift checks</td></tr>
<tr><td>Manual</td><td>User clicks Run</td><td><code>trigger: none</code></td><td>Production deploys</td></tr>
<tr><td>Pipeline Resource</td><td>Another pipeline completes</td><td><code>resources: {pipelines: [...]}</code></td><td>Chain pipelines</td></tr>
</table>
<h3>Variables β Scope & Precedence</h3>
<table>
<tr><th>Source</th><th>Scope</th><th>Precedence</th><th>Secret Support</th></tr>
<tr><td>YAML inline</td><td>Pipeline/Stage/Job</td><td>Lowest</td><td>No</td></tr>
<tr><td>Variable Group</td><td>Linked to pipeline</td><td>Medium</td><td>Yes (Key Vault)</td></tr>
<tr><td>Pipeline UI</td><td>Pipeline settings</td><td>Medium</td><td>Yes</td></tr>
<tr><td>Runtime parameter</td><td>User input at runtime</td><td>Highest</td><td>No</td></tr>
<tr><td>Predefined</td><td>System-provided</td><td>N/A</td><td>N/A</td></tr>
</table>
<h3>Template Types</h3>
<div class="info-box">
<div class="box-title">π Reusable Pipeline Templates</div>
<div class="box-content">
<strong>Include templates:</strong> Insert steps/jobs/stages from another file (<code>template: steps.yml</code>)<br>
<strong>Extends templates:</strong> Define pipeline structure that teams must follow (<code>extends: template: pipeline.yml</code>)<br>
<strong>Variable templates:</strong> Share variable definitions across pipelines<br>
<strong>Expression templates:</strong> Conditional logic using <code>\${{ if }}</code> expressions<br><br>
<strong>Best Practice:</strong> Use extends templates to enforce security stages (scanning, approvals) that teams cannot skip.
</div>
</div>
<h3>Environments & Approvals</h3>
<div class="callout insight">
<div class="callout-title">π‘ Deployment Jobs vs Regular Jobs</div>
Use <strong>deployment jobs</strong> (not regular jobs) for deployments. They support:<br>
β’ <strong>Environments</strong> β logical targets (dev, staging, prod)<br>
β’ <strong>Approval gates</strong> β manual or automated checks before deploy<br>
β’ <strong>Deployment strategies</strong> β runOnce, rolling, canary<br>
β’ <strong>Deployment history</strong> β audit trail of what deployed where
</div>
`,
handson: `
<h3>Complete Multi-Stage YAML Pipeline</h3>
<div class="code-block">
<span class="comment"># azure-pipelines.yml β Full CI/CD Pipeline</span>
<span class="key">trigger</span>:
<span class="key">branches</span>:
<span class="key">include</span>: [main]
<span class="key">paths</span>:
<span class="key">exclude</span>: [docs/*, README.md]
<span class="key">variables</span>:
<span class="key">dockerRegistry</span>: <span class="string">"myacr.azurecr.io"</span>
<span class="key">imageName</span>: <span class="string">"bankapp"</span>
<span class="key">imageTag</span>: <span class="string">"$(Build.BuildId)"</span>
<span class="key">k8sNamespace</span>: <span class="string">"default"</span>
<span class="key">stages</span>:
- <span class="key">stage</span>: Compile
<span class="key">displayName</span>: <span class="string">"Compile Stage"</span>
<span class="key">jobs</span>:
- <span class="key">job</span>: compile
<span class="key">pool</span>:
<span class="key">name</span>: <span class="string">"myagentpool"</span>
<span class="key">steps</span>:
- <span class="key">task</span>: Maven@4
<span class="key">inputs</span>:
<span class="key">mavenPomFile</span>: <span class="string">"pom.xml"</span>
<span class="key">goals</span>: <span class="string">"compile"</span>
- <span class="key">stage</span>: Test
<span class="key">dependsOn</span>: Compile
<span class="key">jobs</span>:
- <span class="key">job</span>: test
<span class="key">steps</span>:
- <span class="key">task</span>: Maven@4
<span class="key">inputs</span>:
<span class="key">goals</span>: <span class="string">"test"</span>
- <span class="key">task</span>: PublishTestResults@2
<span class="key">inputs</span>:
<span class="key">testResultsFormat</span>: <span class="string">"JUnit"</span>
<span class="key">testResultsFiles</span>: <span class="string">"**/TEST-*.xml"</span>
- <span class="key">stage</span>: SecurityScan
<span class="key">dependsOn</span>: Test
<span class="key">jobs</span>:
- <span class="key">job</span>: trivy_scan
<span class="key">steps</span>:
- <span class="key">script</span>: |
trivy fs --format table -o report.html .
<span class="key">displayName</span>: <span class="string">"Trivy FS Scan"</span>
- <span class="key">stage</span>: CodeQuality
<span class="key">dependsOn</span>: SecurityScan
<span class="key">displayName</span>: <span class="string">"SonarQube Analysis"</span>
- <span class="key">stage</span>: BuildImage
<span class="key">dependsOn</span>: CodeQuality
<span class="key">displayName</span>: <span class="string">"Docker Build & Push"</span>
- <span class="key">stage</span>: Deploy
<span class="key">dependsOn</span>: BuildImage
<span class="key">displayName</span>: <span class="string">"Deploy to AKS"</span>
</div>
<h3>Runtime Parameters</h3>
<div class="code-block">
<span class="comment"># Allow users to choose environment at runtime</span>
<span class="key">parameters</span>:
- <span class="key">name</span>: environment
<span class="key">displayName</span>: <span class="string">"Target Environment"</span>
<span class="key">type</span>: string
<span class="key">default</span>: <span class="string">"dev"</span>
<span class="key">values</span>: [<span class="string">"dev"</span>, <span class="string">"staging"</span>, <span class="string">"production"</span>]
- <span class="key">name</span>: skipTests
<span class="key">displayName</span>: <span class="string">"Skip Tests?"</span>
<span class="key">type</span>: boolean
<span class="key">default</span>: false
<span class="key">stages</span>:
- <span class="key">stage</span>: Test
<span class="key">condition</span>: eq(<span class="string">'\${{ parameters.skipTests }}'</span>, false)
<span class="key">jobs</span>:
- <span class="key">job</span>: test
<span class="key">steps</span>:
- <span class="key">script</span>: echo <span class="string">"Running tests..."</span>
- <span class="key">stage</span>: Deploy
<span class="key">jobs</span>:
- <span class="key">deployment</span>: deploy_app
<span class="key">environment</span>: <span class="string">"\${{ parameters.environment }}"</span>
<span class="key">strategy</span>:
<span class="key">runOnce</span>:
<span class="key">deploy</span>:
<span class="key">steps</span>:
- <span class="key">script</span>: echo <span class="string">"Deploying to \${{ parameters.environment }}"</span>
</div>
<h3>Pipeline Templates (Reuse)</h3>
<div class="code-block">
<span class="comment"># templates/build-stage.yml β Reusable build template</span>
<span class="key">parameters</span>:
- <span class="key">name</span>: projectPath
<span class="key">type</span>: string
- <span class="key">name</span>: buildConfiguration
<span class="key">type</span>: string
<span class="key">default</span>: <span class="string">"Release"</span>
<span class="key">stages</span>:
- <span class="key">stage</span>: Build
<span class="key">jobs</span>:
- <span class="key">job</span>: build
<span class="key">steps</span>:
- <span class="key">task</span>: Maven@4
<span class="key">inputs</span>:
<span class="key">mavenPomFile</span>: <span class="string">"\${{ parameters.projectPath }}/pom.xml"</span>
<span class="key">goals</span>: <span class="string">"package"</span>
<span class="comment"># Main pipeline β uses the template</span>
<span class="key">trigger</span>: [main]
<span class="key">stages</span>:
- <span class="key">template</span>: templates/build-stage.yml
<span class="key">parameters</span>:
<span class="key">projectPath</span>: <span class="string">"src/backend"</span>
</div>
<h3>Matrix Strategy (Parallel Builds)</h3>
<div class="code-block">
<span class="comment"># Build across multiple configurations simultaneously</span>
<span class="key">jobs</span>:
- <span class="key">job</span>: Build
<span class="key">strategy</span>:
<span class="key">matrix</span>:
<span class="key">java11</span>:
<span class="key">jdkVersion</span>: <span class="string">"1.11"</span>
<span class="key">java17</span>:
<span class="key">jdkVersion</span>: <span class="string">"1.17"</span>
<span class="key">java21</span>:
<span class="key">jdkVersion</span>: <span class="string">"1.21"</span>
<span class="key">maxParallel</span>: 3
<span class="key">steps</span>:
- <span class="key">task</span>: JavaToolInstaller@0
<span class="key">inputs</span>:
<span class="key">versionSpec</span>: <span class="string">"$(jdkVersion)"</span>
- <span class="key">script</span>: mvn test
</div>
`,
applications: `
<h3>Pipeline Architecture Patterns</h3>
<div class="pipeline-flow">
<div class="pipeline-stage" style="background: rgba(0,120,212,0.2); color: #0078D4;">Compile</div>
<span class="pipeline-arrow">β</span>
<div class="pipeline-stage" style="background: rgba(0,183,195,0.2); color: #00b7c3;">Test</div>
<span class="pipeline-arrow">β</span>
<div class="pipeline-stage" style="background: rgba(231,76,60,0.2); color: #e74c3c;">Trivy Scan</div>
<span class="pipeline-arrow">β</span>
<div class="pipeline-stage" style="background: rgba(163,113,247,0.2); color: #a371f7;">SonarQube</div>
<span class="pipeline-arrow">β</span>
<div class="pipeline-stage" style="background: rgba(36,150,237,0.2); color: #2496ED;">Docker Build</div>
<span class="pipeline-arrow">β</span>
<div class="pipeline-stage" style="background: rgba(255,107,53,0.2); color: #ff6b35;">Image Scan</div>
<span class="pipeline-arrow">β</span>
<div class="pipeline-stage" style="background: rgba(0,255,136,0.2); color: #00ff88;">Push ACR</div>
<span class="pipeline-arrow">β</span>
<div class="pipeline-stage" style="background: rgba(46,204,113,0.2); color: #2ecc71;">Deploy AKS</div>
</div>
<h3>Pipeline Optimization Tips</h3>
<div class="info-box">
<div class="box-title">β‘ Speed Up Your Pipelines</div>
<div class="box-content">
<strong>Caching:</strong> Cache Maven/npm dependencies between runs (<code>Cache@2</code> task)<br>
<strong>Parallel jobs:</strong> Run independent stages simultaneously (remove dependsOn)<br>
<strong>Path triggers:</strong> Only trigger on changed paths (<code>paths: {include: [src/]}</code>)<br>
<strong>Incremental builds:</strong> Only rebuild changed modules<br>
<strong>Self-hosted agents:</strong> Pre-install tools, avoid download time<br>
<strong>Docker layer caching:</strong> Cache Docker build layers in ACR
</div>
</div>
<div class="interview-box">
<div class="box-title">π Interview Questions & Answers</div>
<div class="box-content">
<strong>1. What are the main YAML pipeline components?</strong><br>
Trigger (when), Pool (where), Variables (config), Stages β Jobs β Steps (what). Stages are logical groups, jobs run on agents, steps are individual tasks.<br><br>
<strong>2. Stages vs Jobs vs Steps β what's the difference?</strong><br>
Stages: logical phases (Build, Test, Deploy) with dependencies. Jobs: units of work that run on an agent. Steps: individual commands/tasks within a job. Stages contain jobs, jobs contain steps.<br><br>
<strong>3. What are pipeline trigger types?</strong><br>
CI (branch push), PR (pull request), Scheduled (cron), Manual (trigger: none), Pipeline Resource (triggered by another pipeline completing). Path filters limit triggers to specific file changes.<br><br>
<strong>4. How do you use variables and variable groups?</strong><br>
Inline variables in YAML, variable groups (shared across pipelines), Key Vault-linked groups for secrets, runtime parameters for user input. Precedence: runtime > UI > variable group > YAML.<br><br>
<strong>5. Microsoft-hosted vs self-hosted agents?</strong><br>
MS-hosted: zero maintenance, clean VM each run, limited to 6hrs. Self-hosted: you manage, persistent, no time limit, pre-installed tools, can access internal resources. Use self-hosted for private networks and custom tooling.<br><br>
<strong>6. How do you create multi-stage pipelines with dependencies?</strong><br>
Use dependsOn to define stage order. Stages run sequentially by default. For parallel: remove dependsOn or set parallel stages. For conditional: use condition expressions.<br><br>
<strong>7. What are pipeline templates?</strong><br>
Reusable YAML files for steps, jobs, or stages. Include templates insert content. Extends templates enforce structure. Used for: DRY code, enforcing security stages, standardizing pipelines across teams.<br><br>
<strong>8. How do you implement approval gates?</strong><br>
Create Environments in Azure DevOps (dev, staging, prod). Add approval checks (manual approvers, branch control, business hours). Use deployment jobs that reference environments. Approvers get notified before deploy.<br><br>
<strong>9. YAML vs Classic editor β when to use which?</strong><br>
YAML: version controlled, code review, templatable, recommended for all new pipelines. Classic: visual editor, good for learning, limited reusability. Microsoft recommends YAML for all scenarios.<br><br>
<strong>10. How do you pass variables between stages?</strong><br>
Use output variables: set in a step with <code>##vso[task.setvariable variable=NAME;isOutput=true]</code>, consume in later stages with <code>dependencies.StageName.outputs['jobName.stepName.NAME']</code>.<br><br>
<strong>11. What is pipeline caching and how does it help?</strong><br>
Cache@2 task stores/restores files between runs (Maven .m2, npm node_modules). Keyed by lock file hash. Can reduce build times by 50-80% for dependency-heavy projects.<br><br>
<strong>12. How does matrix strategy work?</strong><br>
Runs the same job with different variable values simultaneously. Example: test across Java 11, 17, 21. maxParallel controls concurrency. Great for cross-platform/cross-version testing.
</div>
</div>
`
},
"build-test": {
concepts: `
<h3>Build Stage β Maven Lifecycle</h3>
<p>The first stage in the CI pipeline compiles source code, runs tests, and packages the application.</p>
<div class="info-box">
<div class="box-title">π¨ Maven Build Lifecycle (Complete)</div>
<div class="box-content">
<strong>validate</strong> β Check project is correct and all dependencies available<br>
<strong>compile</strong> β Compile source code (.java β .class)<br>
<strong>test</strong> β Run unit tests with JUnit/TestNG<br>
<strong>package</strong> β Create JAR/WAR file<br>
<strong>verify</strong> β Run integration tests and quality checks<br>
<strong>install</strong> β Install package to local Maven repository<br>
<strong>deploy</strong> β Push to remote repository (Nexus/Artifactory)
</div>
</div>
<h3>Test Pyramid</h3>
<table>
<tr><th>Level</th><th>Type</th><th>Speed</th><th>Cost</th><th>Coverage Target</th><th>Tools</th></tr>
<tr><td><strong>Top</strong></td><td>E2E Tests</td><td>Slowest</td><td>Highest</td><td>~10%</td><td>Selenium, Cypress, Playwright</td></tr>
<tr><td><strong>Middle</strong></td><td>Integration Tests</td><td>Medium</td><td>Medium</td><td>~20%</td><td>Spring Test, Testcontainers</td></tr>
<tr><td><strong>Bottom</strong></td><td>Unit Tests</td><td>Fastest</td><td>Lowest</td><td>~70%</td><td>JUnit, Mockito, pytest</td></tr>
<tr><td><strong>Foundation</strong></td><td>Static Analysis</td><td>Instant</td><td>Free</td><td>100%</td><td>SonarQube, ESLint, Pylint</td></tr>
</table>
<h3>Code Quality β SonarQube Deep Dive</h3>
<table>
<tr><th>Metric</th><th>What It Measures</th><th>Quality Gate</th><th>Impact</th></tr>
<tr><td><strong>Bugs</strong></td><td>Code errors causing failures</td><td>0 new bugs</td><td>Reliability</td></tr>
<tr><td><strong>Vulnerabilities</strong></td><td>Security weaknesses</td><td>0 new vulnerabilities</td><td>Security</td></tr>
<tr><td><strong>Code Smells</strong></td><td>Maintainability issues</td><td>A rating</td><td>Technical Debt</td></tr>
<tr><td><strong>Coverage</strong></td><td>% of code tested</td><td>β₯ 80%</td><td>Confidence</td></tr>
<tr><td><strong>Duplications</strong></td><td>Copy-pasted code</td><td>< 3%</td><td>Maintenance</td></tr>
<tr><td><strong>Hotspots</strong></td><td>Security-sensitive code</td><td>Reviewed</td><td>Risk</td></tr>
</table>
<h3>Security Scanning β SAST vs DAST vs SCA</h3>
<table>
<tr><th>Type</th><th>What</th><th>When</th><th>Tools</th><th>Finds</th></tr>
<tr><td><strong>SAST</strong></td><td>Static Application Security Testing</td><td>During CI (code analysis)</td><td>SonarQube, Checkmarx, Semgrep</td><td>SQL injection, XSS, buffer overflow</td></tr>
<tr><td><strong>DAST</strong></td><td>Dynamic Application Security Testing</td><td>Against running app</td><td>OWASP ZAP, Burp Suite</td><td>Runtime vulnerabilities, auth issues</td></tr>
<tr><td><strong>SCA</strong></td><td>Software Composition Analysis</td><td>During CI (dependency check)</td><td>Trivy, Snyk, OWASP Dependency-Check</td><td>Known CVEs in libraries</td></tr>
<tr><td><strong>IaC Scan</strong></td><td>Infrastructure as Code scanning</td><td>During CI</td><td>Trivy config, Checkov, tfsec</td><td>Misconfigurations in Terraform/K8s</td></tr>
</table>
<h3>Trivy β Multi-Scanner</h3>
<table>
<tr><th>Scan Type</th><th>Command</th><th>What It Scans</th><th>Pipeline Stage</th></tr>
<tr><td>File System</td><td><code>trivy fs .</code></td><td>Dependencies, configs</td><td>Before Docker build</td></tr>
<tr><td>Image</td><td><code>trivy image myimage:tag</code></td><td>Docker image layers + OS packages</td><td>After Docker build</td></tr>
<tr><td>Config</td><td><code>trivy config .</code></td><td>Terraform, K8s manifests</td><td>Before deploy</td></tr>
<tr><td>Repository</td><td><code>trivy repo .</code></td><td>Git repository</td><td>PR validation</td></tr>
</table>
<div class="callout insight">
<div class="callout-title">π‘ Defense in Depth</div>
The pipeline runs TWO Trivy scans: first on the file system (before Docker build), then on the built Docker image (before push to ACR). This catches vulnerabilities at both the dependency layer and the container OS layer.
</div>
`,
handson: `
<h3>SonarQube Setup</h3>
<div class="code-block">
<span class="comment"># Install Docker on SonarQube VM</span>
<span class="keyword">sudo</span> apt-get update
<span class="keyword">sudo</span> apt-get install docker.io -y
<span class="keyword">sudo</span> usermod -aG docker ubuntu
<span class="comment"># Run SonarQube container</span>
<span class="keyword">docker</span> run -d --name sonarqube \\
-p 9000:9000 \\
-v sonarqube_data:/opt/sonarqube/data \\
-v sonarqube_logs:/opt/sonarqube/logs \\
sonarqube:lts-community
<span class="comment"># Access at http://<VM-IP>:9000</span>
<span class="comment"># Default login: admin / admin (change immediately!)</span>
<span class="comment"># Generate token: My Account β Security β Generate Token</span>
</div>
<h3>SonarQube Pipeline Stage</h3>
<div class="code-block">
<span class="comment"># SonarQube Analysis Stage</span>
- <span class="key">stage</span>: SonarQube
<span class="key">displayName</span>: <span class="string">"SonarQube Analysis"</span>
<span class="key">jobs</span>:
- <span class="key">job</span>: sonarqube
<span class="key">steps</span>:
- <span class="key">task</span>: SonarQubePrepare@6
<span class="key">inputs</span>:
<span class="key">SonarQube</span>: <span class="string">"sonar-conn"</span>
<span class="key">scannerMode</span>: <span class="string">"Other"</span>
<span class="key">extraProperties</span>: |
sonar.projectKey=bankapp
sonar.java.coveragePlugin=jacoco
sonar.coverage.jacoco.xmlReportPaths=target/site/jacoco/jacoco.xml
- <span class="key">task</span>: Maven@4
<span class="key">inputs</span>:
<span class="key">goals</span>: <span class="string">"verify"</span>
<span class="key">sonarQubeRunAnalysis</span>: true
- <span class="key">task</span>: SonarQubePublish@6
<span class="key">inputs</span>:
<span class="key">pollingTimeoutSec</span>: <span class="string">"300"</span>
</div>
<h3>Trivy Scan Stages</h3>
<div class="code-block">
<span class="comment"># Trivy File System Scan β catches dependency CVEs</span>
- <span class="key">stage</span>: trivy_fs_scan
<span class="key">jobs</span>:
- <span class="key">job</span>: trivy_scan
<span class="key">steps</span>:
- <span class="key">script</span>: |
trivy fs --format table -o fs-report.html .
trivy fs --severity HIGH,CRITICAL --exit-code 1 .
<span class="key">displayName</span>: <span class="string">"Trivy File System Scan"</span>
<span class="comment"># Trivy Image Scan β catches container OS CVEs</span>
- <span class="key">stage</span>: trivy_image_scan
<span class="key">jobs</span>:
- <span class="key">job</span>: trivy_image
<span class="key">steps</span>:
- <span class="key">script</span>: |
trivy image --severity HIGH,CRITICAL \\
--exit-code 1 \\
--ignore-unfixed \\
myacr.azurecr.io/dev:latest
<span class="key">displayName</span>: <span class="string">"Trivy Image Scan"</span>
</div>
<h3>Code Coverage Enforcement</h3>
<div class="code-block">
<span class="comment"># pom.xml β JaCoCo plugin for code coverage</span>
<<span class="keyword">plugin</span>>
<<span class="key">groupId</span>>org.jacoco</<span class="key">groupId</span>>
<<span class="key">artifactId</span>>jacoco-maven-plugin</<span class="key">artifactId</span>>
<<span class="key">executions</span>>
<<span class="keyword">execution</span>>
<<span class="key">goals</span>><<span class="keyword">goal</span>>prepare-agent</<span class="keyword">goal</span>></<span class="key">goals</span>>
</<span class="keyword">execution</span>>
<<span class="keyword">execution</span> <span class="key">id</span>=<span class="string">"check"</span>>
<<span class="key">goals</span>><<span class="keyword">goal</span>>check</<span class="keyword">goal</span>></<span class="key">goals</span>>
<<span class="key">configuration</span>>
<<span class="key">rules</span>>
<<span class="keyword">rule</span>>
<<span class="key">limits</span>>
<<span class="keyword">limit</span>>
<<span class="key">minimum</span>><span class="string">0.80</span></<span class="key">minimum</span>>
</<span class="keyword">limit</span>>
</<span class="key">limits</span>>
</<span class="keyword">rule</span>>
</<span class="key">rules</span>>
</<span class="key">configuration</span>>
</<span class="keyword">execution</span>>
</<span class="key">executions</span>>
</<span class="keyword">plugin</span>>
</div>
`,
applications: `
<h3>Quality Gate Strategy</h3>
<div class="info-box">
<div class="box-title">π‘οΈ Defense in Depth β 5 Layers</div>
<div class="box-content">
<strong>Layer 1:</strong> Pre-commit hooks β Lint, format, basic checks (instant feedback)<br>
<strong>Layer 2:</strong> SAST β SonarQube static analysis β Catch code smells and bugs<br>
<strong>Layer 3:</strong> Unit Tests β Maven test with JaCoCo coverage β Catch logic errors<br>
<strong>Layer 4:</strong> SCA β Trivy fs scan β Catch dependency CVEs<br>
<strong>Layer 5:</strong> Container Scan β Trivy image scan β Catch container OS CVEs<br>
<strong>Bonus:</strong> DAST β OWASP ZAP against staging β Catch runtime vulnerabilities
</div>
</div>
<h3>OWASP Top 10 (2021) β What Scanners Detect</h3>
<table>
<tr><th>#</th><th>Vulnerability</th><th>Detected By</th></tr>
<tr><td>A01</td><td>Broken Access Control</td><td>DAST, Code Review</td></tr>
<tr><td>A02</td><td>Cryptographic Failures</td><td>SAST, SCA</td></tr>
<tr><td>A03</td><td>Injection (SQL, XSS)</td><td>SAST, DAST</td></tr>
<tr><td>A04</td><td>Insecure Design</td><td>Threat Modeling</td></tr>
<tr><td>A05</td><td>Security Misconfiguration</td><td>IaC Scan, DAST</td></tr>
<tr><td>A06</td><td>Vulnerable Components</td><td>SCA (Trivy, Snyk)</td></tr>
<tr><td>A07</td><td>Authentication Failures</td><td>DAST, Pen Testing</td></tr>
<tr><td>A08</td><td>Software Integrity Failures</td><td>SCA, Supply Chain</td></tr>
<tr><td>A09</td><td>Logging & Monitoring Failures</td><td>Manual Review</td></tr>
<tr><td>A10</td><td>Server-Side Request Forgery</td><td>SAST, DAST</td></tr>
</table>
<div class="interview-box">
<div class="box-title">π Interview Questions & Answers</div>
<div class="box-content">
<strong>1. What is the Maven build lifecycle?</strong><br>
7 phases: validate β compile β test β package β verify β install β deploy. Each phase runs all previous phases. <code>mvn package</code> runs validate, compile, test, then package.<br><br>
<strong>2. What is SonarQube and what does it measure?</strong><br>
Static code analysis platform. Measures: bugs (reliability), vulnerabilities (security), code smells (maintainability), coverage (test %), duplications (DRY), security hotspots. Uses quality gates to pass/fail builds.<br><br>
<strong>3. Explain Quality Gates.</strong><br>
Configurable thresholds in SonarQube that determine if code passes: 0 new bugs, 0 new vulnerabilities, β₯80% coverage on new code, <3% duplication. Pipeline fails if gate fails.<br><br>
<strong>4. What is Trivy and how does it differ from OWASP Dependency-Check?</strong><br>
Both are SCA tools. Trivy: multi-purpose (fs, image, config, repo), fast, zero-config. OWASP DC: dependency-only, uses NVD database, more detailed reports. Trivy is preferred for container scanning.<br><br>
<strong>5. Why run both file system and image scans?</strong><br>
FS scan catches vulnerable dependencies in your code (pom.xml, package.json). Image scan catches vulnerabilities in the container OS and system packages. Different layers, different CVEs.<br><br>
<strong>6. What is SAST vs DAST vs SCA?</strong><br>
SAST: analyzes source code without running it (finds code-level bugs). DAST: tests running application (finds runtime issues). SCA: checks third-party dependencies for known CVEs. All three should be in your pipeline.<br><br>
<strong>7. What is a "code smell" vs a "bug" vs a "vulnerability"?</strong><br>
Bug: code that will cause incorrect behavior. Vulnerability: code exploitable by attackers. Code smell: maintainability issue (long methods, dead code). Smells don't break things but increase technical debt.<br><br>
<strong>8. How do you publish test results in Azure Pipelines?</strong><br>
Use PublishTestResults@2 task with format (JUnit/NUnit), path to XML results. Results appear in pipeline run's "Tests" tab with pass/fail breakdown and trend charts.<br><br>
<strong>9. How would you fail a pipeline if coverage drops below 80%?</strong><br>
Two options: JaCoCo check goal in pom.xml (fails Maven build), or SonarQube quality gate with coverage threshold. JaCoCo is faster (no SonarQube call), quality gate is more comprehensive.<br><br>
<strong>10. Explain the test pyramid.</strong><br>
Bottom: many fast unit tests (70%). Middle: moderate integration tests (20%). Top: few slow E2E tests (10%). Foundation: static analysis (100%). Inverted pyramid (too many E2E) leads to slow, flaky pipelines.
</div>
</div>
`
},
"docker": {
concepts: `
<h3>What is Docker?</h3>
<p>Docker is a platform for building, shipping, and running applications in <strong>containers</strong> β lightweight, portable, self-sufficient units that package code with all its dependencies.</p>
<h3>Docker Internals β How Containers Work</h3>
<div class="info-box">
<div class="box-title">π§ Linux Kernel Features Behind Docker</div>
<div class="box-content">
<strong>Namespaces:</strong> Process isolation β each container has its own PID, network, mount, user, IPC namespace<br>
<strong>cgroups:</strong> Resource limits β control CPU, memory, disk I/O per container<br>
<strong>Union File System:</strong> Layered storage β OverlayFS stacks read-only image layers + read-write container layer<br>
<strong>Container Runtime:</strong> containerd (Docker default) or CRI-O (Kubernetes native)
</div>
</div>
<h3>Docker Architecture</h3>
<table>
<tr><th>Component</th><th>Description</th><th>Example</th></tr>
<tr><td><strong>Image</strong></td><td>Read-only template (layers of instructions)</td><td>openjdk:17-alpine</td></tr>
<tr><td><strong>Container</strong></td><td>Running instance of an image (writable layer)</td><td>bankapp-container</td></tr>
<tr><td><strong>Dockerfile</strong></td><td>Instructions to build an image</td><td>FROM, RUN, COPY, CMD</td></tr>
<tr><td><strong>Registry</strong></td><td>Image storage (Docker Hub, ACR, ECR)</td><td>myacr.azurecr.io/app:v1</td></tr>
<tr><td><strong>Volume</strong></td><td>Persistent storage outside container lifecycle</td><td>Database data, logs</td></tr>
<tr><td><strong>Network</strong></td><td>Communication between containers</td><td>bridge, host, overlay</td></tr>
</table>
<h3>Docker vs Virtual Machines</h3>
<table>
<tr><th>Feature</th><th>Docker Container</th><th>Virtual Machine</th></tr>
<tr><td>Boot Time</td><td>Milliseconds to seconds</td><td>Minutes</td></tr>
<tr><td>Size</td><td>MBs (Alpine: 5MB)</td><td>GBs</td></tr>
<tr><td>Isolation</td><td>Process-level (shared kernel)</td><td>Full OS-level (own kernel)</td></tr>
<tr><td>Performance</td><td>Near-native</td><td>Hypervisor overhead (~10%)</td></tr>
<tr><td>Density</td><td>100s per host</td><td>10s per host</td></tr>
<tr><td>Security</td><td>Shared kernel = smaller boundary</td><td>Stronger isolation</td></tr>
<tr><td>Use Case</td><td>Microservices, CI/CD</td><td>Legacy apps, different OS</td></tr>
</table>
<h3>Docker Networking Modes</h3>
<table>
<tr><th>Mode</th><th>Description</th><th>Use Case</th></tr>
<tr><td><strong>bridge</strong></td><td>Default. Containers get private IP, NAT for external</td><td>Most applications</td></tr>
<tr><td><strong>host</strong></td><td>Container uses host's network directly</td><td>High performance (no NAT overhead)</td></tr>
<tr><td><strong>none</strong></td><td>No networking</td><td>Security-sensitive batch jobs</td></tr>
<tr><td><strong>overlay</strong></td><td>Multi-host networking (Swarm/K8s)</td><td>Container orchestration</td></tr>
</table>
<h3>Azure Container Registry (ACR)</h3>
<div class="info-box">
<div class="box-title">π¦ ACR Features</div>
<div class="box-content">
<strong>SKUs:</strong> Basic ($0.17/day), Standard ($0.67/day), Premium ($1.67/day β geo-replication, private link)<br>
<strong>Features:</strong> Geo-replication, image scanning, webhook triggers, content trust, retention policies<br>
<strong>Integration:</strong> Native integration with AKS (no credentials needed with managed identity)<br>
<strong>ACR Tasks:</strong> Build images in the cloud (no local Docker needed)
</div>
</div>
`,
handson: `
<h3>Dockerfile Best Practices</h3>
<div class="code-block">
<span class="comment"># Multi-stage build for a Java application</span>
<span class="comment"># Stage 1: Build (large image with build tools)</span>
<span class="keyword">FROM</span> maven:3.9-eclipse-temurin-17 <span class="keyword">AS</span> build
<span class="key">WORKDIR</span> /app
<span class="key">COPY</span> pom.xml .
<span class="keyword">RUN</span> mvn dependency:go-offline <span class="comment"># Cache dependencies</span>
<span class="key">COPY</span> src/ ./src/
<span class="keyword">RUN</span> mvn package -DskipTests
<span class="comment"># Stage 2: Runtime (minimal image)</span>
<span class="keyword">FROM</span> eclipse-temurin:17-jre-alpine
<span class="keyword">RUN</span> addgroup -S appgroup && adduser -S appuser -G appgroup
<span class="key">WORKDIR</span> /app
<span class="key">COPY</span> --from=build /app/target/*.jar app.jar
<span class="keyword">USER</span> appuser
<span class="key">EXPOSE</span> 8080
<span class="key">HEALTHCHECK</span> --interval=30s --timeout=3s \\
CMD wget --no-verbose --tries=1 http://localhost:8080/actuator/health || exit 1
<span class="key">ENTRYPOINT</span> [<span class="string">"java"</span>, <span class="string">"-jar"</span>, <span class="string">"app.jar"</span>]
</div>
<h3>Docker Pipeline Stages</h3>
<div class="code-block">
<span class="comment"># Build, Scan, and Push Docker Image</span>
- <span class="key">stage</span>: DockerBuild
<span class="key">displayName</span>: <span class="string">"Build Docker Image"</span>
<span class="key">jobs</span>:
- <span class="key">job</span>: docker_build
<span class="key">steps</span>:
- <span class="key">task</span>: Docker@2
<span class="key">inputs</span>:
<span class="key">containerRegistry</span>: <span class="string">"acr-service-conn"</span>
<span class="key">repository</span>: <span class="string">"bankapp"</span>
<span class="key">command</span>: <span class="string">"build"</span>
<span class="key">tags</span>: |
$(Build.BuildId)
latest
- <span class="key">stage</span>: ImageScan
<span class="key">displayName</span>: <span class="string">"Scan Docker Image"</span>
<span class="key">jobs</span>:
- <span class="key">job</span>: scan
<span class="key">steps</span>:
- <span class="key">script</span>: |
trivy image --severity HIGH,CRITICAL \\
--exit-code 1 \\
myacr.azurecr.io/bankapp:$(Build.BuildId)
- <span class="key">stage</span>: DockerPush
<span class="key">displayName</span>: <span class="string">"Push to ACR"</span>
<span class="key">jobs</span>:
- <span class="key">job</span>: docker_push
<span class="key">steps</span>:
- <span class="key">task</span>: Docker@2
<span class="key">inputs</span>:
<span class="key">containerRegistry</span>: <span class="string">"acr-service-conn"</span>
<span class="key">repository</span>: <span class="string">"bankapp"</span>
<span class="key">command</span>: <span class="string">"push"</span>
<span class="key">tags</span>: |
$(Build.BuildId)
latest
</div>
<h3>Docker Compose for Local Development</h3>
<div class="code-block">
<span class="comment"># docker-compose.yml β Local dev environment</span>
<span class="key">version</span>: <span class="string">"3.8"</span>
<span class="key">services</span>:
<span class="key">app</span>:
<span class="key">build</span>: .
<span class="key">ports</span>: [<span class="string">"8080:8080"</span>]
<span class="key">environment</span>:
- <span class="string">SPRING_DATASOURCE_URL=jdbc:mysql://db:3306/bankdb</span>
<span class="key">depends_on</span>: [db]
<span class="key">db</span>:
<span class="key">image</span>: <span class="string">mysql:8.0</span>
<span class="key">environment</span>:
<span class="key">MYSQL_ROOT_PASSWORD</span>: <span class="string">rootpass</span>
<span class="key">MYSQL_DATABASE</span>: <span class="string">bankdb</span>
<span class="key">volumes</span>:
- <span class="string">db_data:/var/lib/mysql</span>
<span class="key">ports</span>: [<span class="string">"3306:3306"</span>]
<span class="key">sonarqube</span>:
<span class="key">image</span>: <span class="string">sonarqube:lts-community</span>
<span class="key">ports</span>: [<span class="string">"9000:9000"</span>]
<span class="key">volumes</span>:
<span class="key">db_data</span>:
</div>
<h3>Essential Docker Commands</h3>
<div class="code-block">
<span class="comment"># Build, run, manage</span>
<span class="keyword">docker</span> build -t myapp:v1 .
<span class="keyword">docker</span> run -d -p 8080:8080 --name myapp myapp:v1
<span class="keyword">docker</span> ps <span class="comment"># List running containers</span>
<span class="keyword">docker</span> logs myapp <span class="comment"># View logs</span>
<span class="keyword">docker</span> exec -it myapp sh <span class="comment"># Shell into container</span>
<span class="keyword">docker</span> stop myapp && docker rm myapp
<span class="comment"># Image management</span>
<span class="keyword">docker</span> images <span class="comment"># List images</span>
<span class="keyword">docker</span> image prune -a <span class="comment"># Remove unused images</span>
<span class="keyword">docker</span> history myapp:v1 <span class="comment"># Show layer history</span>
<span class="comment"># Push to ACR</span>
<span class="keyword">az</span> acr login --name myacr
<span class="keyword">docker</span> tag myapp:v1 myacr.azurecr.io/myapp:v1
<span class="keyword">docker</span> push myacr.azurecr.io/myapp:v1
<span class="comment"># ACR Tasks β Build in the cloud (no local Docker!)</span>
<span class="keyword">az</span> acr build --registry myacr --image myapp:v1 .
</div>
`,
applications: `
<h3>Container Best Practices β Production Checklist</h3>
<div class="info-box">
<div class="box-title">β
Production Dockerfile Checklist</div>
<div class="box-content">
<strong>Security:</strong> Don't run as root (USER directive), use minimal base images (Alpine/Distroless)<br>
<strong>Size:</strong> Multi-stage builds, minimize layers, use .dockerignore<br>
<strong>Scanning:</strong> Scan with Trivy before pushing, enable ACR image scanning<br>
<strong>Tagging:</strong> Never use :latest in production β use semantic versioning or build ID<br>
<strong>Health Checks:</strong> Add HEALTHCHECK in Dockerfile for orchestrator integration<br>
<strong>Reproducibility:</strong> Pin base image versions, use lock files for dependencies<br>
<strong>Secrets:</strong> Never bake secrets into images β use env vars or mounted secrets
</div>
</div>
<h3>Image Size Optimization</h3>
<table>
<tr><th>Base Image</th><th>Size</th><th>Use Case</th></tr>
<tr><td>ubuntu:22.04</td><td>~77 MB</td><td>Development, debugging</td></tr>
<tr><td>alpine:3.18</td><td>~5 MB</td><td>Production (most apps)</td></tr>
<tr><td>distroless/java17</td><td>~190 MB</td><td>Production (no shell!)</td></tr>
<tr><td>scratch</td><td>0 MB</td><td>Statically compiled Go/Rust</td></tr>
</table>
<div class="interview-box">
<div class="box-title">π Interview Questions & Answers</div>
<div class="box-content">
<strong>1. Docker image vs container β what's the difference?</strong><br>
Image: read-only template with layered instructions (like a class). Container: running instance of an image with a writable layer (like an object). Multiple containers can share one image.<br><br>
<strong>2. Explain multi-stage builds.</strong><br>
Use multiple FROM statements. Stage 1: build environment with all tools (Maven, npm). Stage 2: minimal runtime (Alpine/JRE). Only final stage is in the output image. Reduces image size by 60-90%.<br><br>
<strong>3. How does Docker differ from a VM?</strong><br>
Docker: shares host kernel, process-level isolation (namespaces + cgroups), MBs, seconds to start. VM: own kernel, full OS isolation (hypervisor), GBs, minutes to start. Docker is lighter but weaker isolation.<br><br>
<strong>4. What is ACR and how do you push images?</strong><br>
Azure Container Registry β managed Docker registry. Push: az acr login, docker tag with ACR URL, docker push. Or use ACR Tasks for cloud builds. Integrates natively with AKS via managed identity.<br><br>
<strong>5. Docker networking modes?</strong><br>
Bridge (default, NAT), Host (no isolation, best performance), None (no network), Overlay (multi-host for orchestration). Bridge is standard, host for performance-critical apps, overlay for K8s.<br><br>
<strong>6. How do you optimize Docker image size?</strong><br>
Multi-stage builds, Alpine/Distroless base, .dockerignore, combine RUN commands (fewer layers), order instructions for cache efficiency (COPY package.json before source), remove build artifacts.<br><br>
<strong>7. What are Docker volumes?</strong><br>
Persistent storage that outlives containers. Types: named volumes (Docker managed), bind mounts (host directory), tmpfs (in-memory). Use for databases, logs, config files that need persistence.<br><br>
<strong>8. Docker Compose vs Kubernetes β when to use which?</strong><br>
Compose: local development, single-host, simple orchestration, docker-compose.yml. K8s: production, multi-host, auto-scaling, self-healing, rolling updates. Compose for dev, K8s for prod.<br><br>
<strong>9. What is a Distroless image?</strong><br>
Google's minimal images containing only the application runtime (no shell, no package manager). More secure (smaller attack surface) but harder to debug. Ideal for production Java, Python, Node.js apps.<br><br>
<strong>10. How does Docker layer caching work?</strong><br>
Each Dockerfile instruction creates a layer. Docker caches layers and reuses them if the instruction + context haven't changed. Order matters: put rarely-changing instructions first (FROM, RUN apt-get) and frequently-changing last (COPY src/).
</div>
</div>
`
},
"kubernetes": {
concepts: `
<h3>What is Kubernetes?</h3>
<p>Kubernetes (K8s) is an open-source <strong>container orchestration platform</strong> that automates deployment, scaling, and management of containerized applications. Originally designed by Google (based on Borg), now maintained by CNCF.</p>
<h3>Kubernetes Architecture</h3>
<div class="info-box">
<div class="box-title">ποΈ Control Plane vs Worker Nodes</div>
<div class="box-content">
<strong>Control Plane (Master):</strong><br>
β’ <strong>API Server</strong> β Entry point for all kubectl commands and REST calls<br>
β’ <strong>etcd</strong> β Distributed key-value store (cluster state & config)<br>
β’ <strong>Scheduler</strong> β Assigns Pods to nodes based on resources, affinity, taints<br>
β’ <strong>Controller Manager</strong> β Runs controllers (Replication, Node, Endpoint, SA)<br>
β’ <strong>Cloud Controller Manager</strong> β Integrates with cloud provider APIs<br><br>
<strong>Worker Nodes:</strong><br>
β’ <strong>kubelet</strong> β Agent that manages Pods on each node<br>
β’ <strong>kube-proxy</strong> β Network rules (iptables/IPVS) for Service routing<br>
β’ <strong>Container Runtime</strong> β containerd (default) or CRI-O
</div>
</div>
<h3>Core Kubernetes Objects</h3>
<table>
<tr><th>Object</th><th>Purpose</th><th>Key Fields</th></tr>
<tr><td><strong>Pod</strong></td><td>Smallest unit β one or more containers</td><td>containers, volumes, restartPolicy</td></tr>
<tr><td><strong>Deployment</strong></td><td>Manages replica sets and rolling updates</td><td>replicas, strategy, selector</td></tr>
<tr><td><strong>Service</strong></td><td>Stable network endpoint for Pods</td><td>type, selector, ports</td></tr>
<tr><td><strong>ConfigMap</strong></td><td>External configuration data</td><td>key-value pairs, mounted as env/files</td></tr>
<tr><td><strong>Secret</strong></td><td>Sensitive data (base64 encoded)</td><td>Opaque, TLS, docker-registry types</td></tr>
<tr><td><strong>Namespace</strong></td><td>Virtual cluster for isolation</td><td>Resource quotas, network policies</td></tr>
<tr><td><strong>Ingress</strong></td><td>HTTP/HTTPS routing and TLS termination</td><td>rules, hosts, paths, TLS</td></tr>
<tr><td><strong>PersistentVolumeClaim</strong></td><td>Request persistent storage</td><td>storageClassName, accessModes, size</td></tr>
<tr><td><strong>HPA</strong></td><td>Horizontal Pod Autoscaler</td><td>minReplicas, maxReplicas, metrics</td></tr>
<tr><td><strong>NetworkPolicy</strong></td><td>Pod-to-pod firewall rules</td><td>ingress, egress, podSelector</td></tr>
</table>
<h3>Service Types</h3>
<table>
<tr><th>Type</th><th>Access</th><th>Use Case</th><th>External IP</th></tr>
<tr><td><strong>ClusterIP</strong></td><td>Internal only</td><td>Inter-service communication</td><td>No</td></tr>
<tr><td><strong>NodePort</strong></td><td>External via node IP:port</td><td>Development, testing</td><td>Node IP:30000-32767</td></tr>
<tr><td><strong>LoadBalancer</strong></td><td>External via cloud LB</td><td>Production (single service)</td><td>Yes (cloud-provisioned)</td></tr>
<tr><td><strong>ExternalName</strong></td><td>DNS CNAME</td><td>External service alias</td><td>No</td></tr>
</table>
<h3>Azure Kubernetes Service (AKS)</h3>
<div class="info-box">
<div class="box-title">βΈοΈ AKS β Managed Kubernetes</div>
<div class="box-content">
<strong>Free control plane:</strong> Microsoft manages API Server, etcd, scheduler (you pay only for worker nodes)<br>
<strong>Auto-scaling:</strong> Cluster autoscaler (nodes) + HPA (pods) + VPA (vertical)<br>
<strong>Networking:</strong> Azure CNI (VNet integration) or kubenet (basic)<br>
<strong>Identity:</strong> Azure AD integration, Managed Identity, Workload Identity<br>
<strong>Monitoring:</strong> Container Insights, Prometheus, Grafana<br>
<strong>Add-ons:</strong> Azure Policy, Key Vault CSI, Dapr, KEDA, GitOps (Flux)
</div>
</div>
<h3>Deployment Strategies in Kubernetes</h3>
<table>
<tr><th>Strategy</th><th>How It Works</th><th>YAML Config</th><th>Rollback</th></tr>
<tr><td><strong>Rolling Update</strong></td><td>Gradually replace old pods</td><td>strategy: {type: RollingUpdate, maxSurge: 1, maxUnavailable: 0}</td><td>kubectl rollout undo</td></tr>
<tr><td><strong>Recreate</strong></td><td>Kill all, then create new</td><td>strategy: {type: Recreate}</td><td>Manual redeploy</td></tr>
<tr><td><strong>Blue-Green</strong></td><td>Two deployments, switch service selector</td><td>Two Deployments + Service label switch</td><td>Switch selector back</td></tr>
<tr><td><strong>Canary</strong></td><td>Multiple deployments with weighted traffic</td><td>Istio/Nginx ingress weighted routing</td><td>Scale down canary</td></tr>
</table>
`,
handson: `
<h3>Kubernetes Manifests</h3>
<div class="code-block">
<span class="comment"># ds.yml β Deployment + Service + ConfigMap</span>
<span class="key">apiVersion</span>: v1
<span class="key">kind</span>: ConfigMap
<span class="key">metadata</span>:
<span class="key">name</span>: bankapp-config
<span class="key">data</span>:
<span class="key">SPRING_PROFILES_ACTIVE</span>: <span class="string">"production"</span>
<span class="key">DB_HOST</span>: <span class="string">"mysql-service"</span>
---
<span class="key">apiVersion</span>: apps/v1
<span class="key">kind</span>: Deployment
<span class="key">metadata</span>:
<span class="key">name</span>: bankapp
<span class="key">spec</span>:
<span class="key">replicas</span>: 3
<span class="key">selector</span>:
<span class="key">matchLabels</span>:
<span class="key">app</span>: bankapp
<span class="key">strategy</span>:
<span class="key">type</span>: RollingUpdate
<span class="key">rollingUpdate</span>:
<span class="key">maxSurge</span>: 1
<span class="key">maxUnavailable</span>: 0
<span class="key">template</span>:
<span class="key">metadata</span>:
<span class="key">labels</span>:
<span class="key">app</span>: bankapp
<span class="key">spec</span>:
<span class="key">containers</span>:
- <span class="key">name</span>: bankapp
<span class="key">image</span>: <span class="string">myacr.azurecr.io/bankapp:latest</span>
<span class="key">ports</span>:
- <span class="key">containerPort</span>: 8080
<span class="key">envFrom</span>:
- <span class="key">configMapRef</span>:
<span class="key">name</span>: bankapp-config
<span class="key">resources</span>:
<span class="key">requests</span>:
<span class="key">cpu</span>: <span class="string">"250m"</span>
<span class="key">memory</span>: <span class="string">"256Mi"</span>
<span class="key">limits</span>:
<span class="key">cpu</span>: <span class="string">"500m"</span>
<span class="key">memory</span>: <span class="string">"512Mi"</span>
<span class="key">readinessProbe</span>:
<span class="key">httpGet</span>:
<span class="key">path</span>: /actuator/health
<span class="key">port</span>: 8080
<span class="key">initialDelaySeconds</span>: 15
<span class="key">livenessProbe</span>:
<span class="key">httpGet</span>:
<span class="key">path</span>: /actuator/health
<span class="key">port</span>: 8080
<span class="key">initialDelaySeconds</span>: 30
---
<span class="key">apiVersion</span>: v1
<span class="key">kind</span>: Service
<span class="key">metadata</span>:
<span class="key">name</span>: bankapp-service
<span class="key">spec</span>:
<span class="key">type</span>: LoadBalancer
<span class="key">selector</span>:
<span class="key">app</span>: bankapp
<span class="key">ports</span>:
- <span class="key">port</span>: 80
<span class="key">targetPort</span>: 8080
</div>
<h3>AKS Deploy Pipeline Stage</h3>
<div class="code-block">
<span class="comment"># Deploy to AKS Stage</span>
- <span class="key">stage</span>: deploy_to_aks
<span class="key">displayName</span>: <span class="string">"Deploy to AKS"</span>
<span class="key">jobs</span>:
- <span class="key">deployment</span>: deploy_to_aks
<span class="key">environment</span>: <span class="string">"production.default"</span>
<span class="key">strategy</span>:
<span class="key">runOnce</span>:
<span class="key">deploy</span>:
<span class="key">steps</span>:
- <span class="key">task</span>: KubernetesManifest@1
<span class="key">inputs</span>:
<span class="key">action</span>: <span class="string">"deploy"</span>
<span class="key">kubernetesServiceConnection</span>: <span class="string">"k8s-conn"</span>
<span class="key">namespace</span>: <span class="string">"default"</span>
<span class="key">manifests</span>: <span class="string">"ds.yml"</span>
<span class="key">containers</span>: <span class="string">"myacr.azurecr.io/bankapp:$(Build.BuildId)"</span>
</div>
<h3>HPA β Horizontal Pod Autoscaler</h3>
<div class="code-block">
<span class="comment"># Auto-scale based on CPU utilization</span>
<span class="key">apiVersion</span>: autoscaling/v2
<span class="key">kind</span>: HorizontalPodAutoscaler
<span class="key">metadata</span>:
<span class="key">name</span>: bankapp-hpa
<span class="key">spec</span>:
<span class="key">scaleTargetRef</span>:
<span class="key">apiVersion</span>: apps/v1
<span class="key">kind</span>: Deployment
<span class="key">name</span>: bankapp
<span class="key">minReplicas</span>: 2
<span class="key">maxReplicas</span>: 10
<span class="key">metrics</span>:
- <span class="key">type</span>: Resource
<span class="key">resource</span>:
<span class="key">name</span>: cpu
<span class="key">target</span>:
<span class="key">type</span>: Utilization
<span class="key">averageUtilization</span>: 70
</div>
<h3>Essential kubectl Commands</h3>
<div class="code-block">
<span class="comment"># Cluster & Node info</span>
<span class="keyword">kubectl</span> cluster-info
<span class="keyword">kubectl</span> get nodes -o wide
<span class="keyword">kubectl</span> top nodes
<span class="comment"># Deploy and manage</span>
<span class="keyword">kubectl</span> apply -f ds.yml
<span class="keyword">kubectl</span> get pods -o wide
<span class="keyword">kubectl</span> get services
<span class="keyword">kubectl</span> get deployments
<span class="comment"># Debugging</span>
<span class="keyword">kubectl</span> describe pod bankapp-xyz
<span class="keyword">kubectl</span> logs bankapp-xyz --follow
<span class="keyword">kubectl</span> exec -it bankapp-xyz -- /bin/sh
<span class="keyword">kubectl</span> get events --sort-by=.metadata.creationTimestamp
<span class="comment"># Scaling & Updates</span>
<span class="keyword">kubectl</span> scale deployment bankapp --replicas=5
<span class="keyword">kubectl</span> rollout status deployment/bankapp
<span class="keyword">kubectl</span> rollout undo deployment/bankapp
<span class="keyword">kubectl</span> rollout history deployment/bankapp
</div>
`,
applications: `
<h3>Production Kubernetes Checklist</h3>
<div class="info-box">
<div class="box-title">β
Production-Ready AKS</div>
<div class="box-content">
β
<strong>Resource Limits:</strong> Set CPU/memory requests and limits on all containers<br>
β
<strong>Health Probes:</strong> Readiness + liveness probes for auto-restart and traffic control<br>
β
<strong>HPA:</strong> Horizontal Pod Autoscaler based on CPU/memory/custom metrics<br>
β
<strong>PDB:</strong> Pod Disruption Budget to ensure availability during updates<br>
β
<strong>Network Policies:</strong> Restrict pod-to-pod communication<br>
β
<strong>RBAC:</strong> Kubernetes RBAC + Azure AD integration<br>
β
<strong>Secrets:</strong> Use Azure Key Vault CSI driver instead of K8s Secrets<br>
β
<strong>Monitoring:</strong> Container Insights + Prometheus + Grafana<br>
β
<strong>Ingress:</strong> Use Ingress controller (NGINX/App Gateway) instead of LoadBalancer per service
</div>
</div>
<h3>Troubleshooting Common Issues</h3>
<table>
<tr><th>Status</th><th>Cause</th><th>Debug Command</th></tr>
<tr><td><strong>CrashLoopBackOff</strong></td><td>App crashes repeatedly</td><td>kubectl logs [pod] --previous</td></tr>
<tr><td><strong>ImagePullBackOff</strong></td><td>Can't pull image</td><td>kubectl describe pod [pod] β check image name/registry auth</td></tr>
<tr><td><strong>Pending</strong></td><td>No schedulable node</td><td>kubectl describe pod β check Events section</td></tr>
<tr><td><strong>OOMKilled</strong></td><td>Out of memory</td><td>Increase memory limits, check for memory leaks</td></tr>
<tr><td><strong>Evicted</strong></td><td>Node under pressure</td><td>kubectl get events, check node resources</td></tr>
</table>
<div class="interview-box">
<div class="box-title">π Interview Questions & Answers</div>
<div class="box-content">
<strong>1. What is Kubernetes and why is it needed?</strong><br>
K8s automates container deployment, scaling, and management. Needed because: containers alone don't handle scheduling, scaling, self-healing, service discovery, or rolling updates. K8s provides all these.<br><br>
<strong>2. Pod vs Deployment vs Service β explain each.</strong><br>
Pod: smallest unit with one or more containers. Deployment: manages Pod replicas, rolling updates, rollbacks. Service: stable network endpoint (DNS name + IP) that routes to Pods via label selector.<br><br>
<strong>3. AKS vs self-managed K8s?</strong><br>
AKS: free managed control plane, automatic upgrades, Azure AD integration, no etcd management. Self-managed: full control, more operational burden, needed for air-gapped or highly customized environments.<br><br>
<strong>4. K8s Service types β explain each.</strong><br>
ClusterIP: internal only (default). NodePort: external via node IP:30000-32767. LoadBalancer: cloud LB with external IP. ExternalName: DNS CNAME alias. Use Ingress for HTTP routing instead of multiple LoadBalancers.<br><br>
<strong>5. Rolling Update vs Blue-Green vs Canary?</strong><br>
Rolling: gradual replacement (built-in). Blue-Green: two deployments, switch service selector (instant switch). Canary: route small % to new version (needs Istio/Nginx). Rolling is default, Blue-Green for zero-downtime, Canary for risk reduction.<br><br>
<strong>6. How do you troubleshoot CrashLoopBackOff?</strong><br>
1) kubectl logs [pod] --previous (check crash reason). 2) kubectl describe pod (check events). 3) Check resource limits (OOMKilled?). 4) Check health probes (failing?). 5) Exec into pod and test manually.<br><br>
<strong>7. What is Helm?</strong><br>
Package manager for Kubernetes. Helm Charts bundle K8s manifests into reusable, versioned packages. Supports templating (values.yaml), dependencies, rollback. Like npm/Maven but for K8s deployments.<br><br>
<strong>8. Readiness vs Liveness probes?</strong><br>
Readiness: "Am I ready to receive traffic?" β fails β pod removed from Service endpoints. Liveness: "Am I still alive?" β fails β pod restarted. Both are essential for production. Common mistake: same endpoint for both.<br><br>
<strong>9. What are Namespaces?</strong><br>
Virtual clusters within a K8s cluster. Use cases: environment separation (dev/staging/prod), team isolation, resource quotas. Default namespaces: default, kube-system, kube-public, kube-node-lease.<br><br>
<strong>10. How do you integrate AKS with Azure DevOps?</strong><br>
Create Kubernetes service connection in Azure DevOps (using kubeconfig or service account). Use KubernetesManifest@1 task in pipeline to deploy manifests. Use deployment jobs with environments for approval gates.
</div>
</div>
`
},
"security": {
concepts: `
<h3>Azure Security Model β Defense in Depth</h3>
<p>Security in Azure DevOps spans identity management, access control, secrets management, and service-to-service authentication across multiple layers.</p>
<h3>Identity & Authentication</h3>
<table>
<tr><th>Identity Type</th><th>What It Is</th><th>Use Case</th><th>Security Level</th></tr>
<tr><td><strong>Service Principal</strong></td><td>App identity in Azure AD</td><td>CI/CD pipeline authentication</td><td>Good (secret-based)</td></tr>
<tr><td><strong>Managed Identity</strong></td><td>Auto-managed identity for Azure resources</td><td>VM/AKS to Azure services</td><td>Best (no secrets)</td></tr>
<tr><td><strong>Workload Identity</strong></td><td>OIDC federation for K8s pods</td><td>K8s pod to Azure services</td><td>Best (no secrets)</td></tr>
<tr><td><strong>PAT (Personal Access Token)</strong></td><td>Alternative to password</td><td>Git auth, REST API</td><td>Moderate (user-scoped)</td></tr>
</table>
<div class="callout insight">
<div class="callout-title">π‘ Security Hierarchy (Best β Worst)</div>
<strong>1. Managed Identity</strong> (no secrets, auto-rotated) β <strong>2. Workload Identity</strong> (OIDC, no secrets) β <strong>3. Service Principal</strong> (secret/cert, manual rotation) β <strong>4. PAT</strong> (user-scoped, expires)
</div>
<h3>Service Connections</h3>
<table>
<tr><th>Connection Type</th><th>Connects To</th><th>Authentication</th><th>Used For</th></tr>
<tr><td><strong>Azure Resource Manager</strong></td><td>Azure subscription</td><td>Service Principal / Managed Identity</td><td>Deploy to Azure services</td></tr>
<tr><td><strong>SonarQube</strong></td><td>SonarQube server</td><td>Token</td><td>Code quality analysis</td></tr>
<tr><td><strong>Kubernetes</strong></td><td>AKS cluster</td><td>Kubeconfig / Service Account</td><td>Deploy manifests</td></tr>
<tr><td><strong>Docker Registry</strong></td><td>ACR / Docker Hub</td><td>Service Principal / Admin user</td><td>Push/pull images</td></tr>
</table>
<h3>Azure Key Vault</h3>
<div class="info-box">
<div class="box-title">π Key Vault β Secrets Management</div>
<div class="box-content">
<strong>What it stores:</strong> Secrets (passwords, connection strings), Keys (encryption keys), Certificates (TLS certs)<br>
<strong>Access control:</strong> RBAC (recommended) or Vault access policies<br>
<strong>Integration:</strong> Variable groups in Azure Pipelines, CSI driver in AKS, App Configuration<br>
<strong>Audit:</strong> Full logging of all secret access in Azure Monitor<br>
<strong>Rotation:</strong> Auto-rotation for storage account keys, manual for others
</div>
</div>
<h3>RBAC in Azure DevOps</h3>
<table>
<tr><th>Level</th><th>Role</th><th>Permissions</th></tr>
<tr><td>Organization</td><td>Collection Admin</td><td>Full control over all projects</td></tr>
<tr><td>Project</td><td>Project Admin</td><td>Full control within project</td></tr>
<tr><td>Project</td><td>Build Admin</td><td>Manage pipeline definitions</td></tr>
<tr><td>Project</td><td>Contributors</td><td>Edit code, run pipelines</td></tr>
<tr><td>Project</td><td>Readers</td><td>View only</td></tr>
<tr><td>Repository</td><td>Per-branch policies</td><td>Enforce reviews, build validation</td></tr>
</table>
<h3>Zero Trust for DevOps</h3>
<div class="callout warning">
<div class="callout-title">β οΈ Zero Trust Principles</div>
<strong>Verify explicitly:</strong> Authenticate and authorize every request<br>
<strong>Least privilege:</strong> Minimum permissions needed for the task<br>
<strong>Assume breach:</strong> Encrypt, segment, monitor as if already compromised<br><br>
Applied to DevOps: branch policies, required reviewers, environment approvals, secret scanning, audit logging, immutable artifacts.
</div>
`,
handson: `
<h3>Creating a Service Principal</h3>
<div class="code-block">
<span class="comment"># Step 1: Create service principal with contributor role</span>
<span class="keyword">az</span> ad sp create-for-rbac \\
--name <span class="string">"devops-pipeline-sp"</span> \\
--role Contributor \\
--scopes /subscriptions/<SUB_ID> \\
--sdk-auth
<span class="comment"># Output: appId, password, tenant (save securely!)</span>
<span class="comment"># Step 2: Use in Azure DevOps Service Connection</span>
<span class="comment"># Project Settings β Service Connections β New β Azure Resource Manager</span>
<span class="comment"># Choose "Service Principal (manual)" β Enter appId, password, tenant</span>
</div>
<h3>Managed Identity Setup</h3>
<div class="code-block">
<span class="comment"># System-assigned identity (auto-created with resource)</span>
<span class="keyword">az</span> vm identity assign \\
--resource-group rg-devops \\
--name agent-vm
<span class="comment"># User-assigned identity (reusable across resources)</span>
<span class="keyword">az</span> identity create \\
--resource-group rg-devops \\
--name pipeline-identity
<span class="comment"># Assign Key Vault access</span>
<span class="keyword">az</span> keyvault set-policy \\
--name my-keyvault \\
--object-id <IDENTITY_PRINCIPAL_ID> \\
--secret-permissions get list
</div>
<h3>Key Vault Integration with Pipelines</h3>
<div class="code-block">
<span class="comment"># Method 1: Variable Group linked to Key Vault</span>
<span class="key">variables</span>:
- <span class="key">group</span>: <span class="string">"kv-secrets"</span> <span class="comment"># Linked to Azure Key Vault in UI</span>
<span class="key">steps</span>:
- <span class="key">script</span>: |
echo "DB Password: $(db-password)"
<span class="key">displayName</span>: <span class="string">"Use secret from Key Vault"</span>
<span class="comment"># Method 2: AzureKeyVault task (more control)</span>
<span class="key">steps</span>:
- <span class="key">task</span>: AzureKeyVault@2
<span class="key">inputs</span>:
<span class="key">azureSubscription</span>: <span class="string">"azure-conn"</span>
<span class="key">keyVaultName</span>: <span class="string">"my-keyvault"</span>
<span class="key">secretsFilter</span>: <span class="string">"db-password,api-key"</span>
- <span class="key">script</span>: |
echo "DB Password: $(db-password)"
echo "API Key: $(api-key)"
</div>
<h3>K8s RBAC + Azure AD</h3>
<div class="code-block">
<span class="comment"># Kubernetes RBAC β Limit namespace access</span>
<span class="key">apiVersion</span>: rbac.authorization.k8s.io/v1
<span class="key">kind</span>: Role
<span class="key">metadata</span>:
<span class="key">namespace</span>: production
<span class="key">name</span>: deployment-manager
<span class="key">rules</span>:
- <span class="key">apiGroups</span>: [<span class="string">"apps"</span>]
<span class="key">resources</span>: [<span class="string">"deployments"</span>]
<span class="key">verbs</span>: [<span class="string">"get"</span>, <span class="string">"list"</span>, <span class="string">"update"</span>, <span class="string">"patch"</span>]
---
<span class="key">apiVersion</span>: rbac.authorization.k8s.io/v1
<span class="key">kind</span>: RoleBinding
<span class="key">metadata</span>:
<span class="key">namespace</span>: production
<span class="key">name</span>: deployer-binding
<span class="key">subjects</span>:
- <span class="key">kind</span>: Group
<span class="key">name</span>: <span class="string">"AAD-GROUP-OBJECT-ID"</span>
<span class="key">roleRef</span>:
<span class="key">kind</span>: Role
<span class="key">name</span>: deployment-manager
</div>
<h3>Secret Scanning Prevention</h3>
<div class="code-block">
<span class="comment"># .gitignore β Never commit secrets</span>
*.env
.env.local
secrets/
*.pem
*.key
<span class="comment"># Pre-commit hook for secret detection</span>
<span class="comment"># Install: pip install detect-secrets</span>
<span class="keyword">detect-secrets</span> scan > .secrets.baseline
<span class="keyword">detect-secrets</span> audit .secrets.baseline
<span class="comment"># Azure DevOps: Enable credential scanning</span>
<span class="comment"># Pipeline β CredScan@3 task scans for leaked passwords, tokens, keys</span>
</div>
`,
applications: `
<h3>Security Checklist for CI/CD</h3>
<div class="info-box">
<div class="box-title">π‘οΈ Production Security Checklist</div>
<div class="box-content">
β
Use Managed Identity or Workload Identity (not Service Principals with secrets)<br>
β
Store all secrets in Azure Key Vault, never in code or pipeline variables<br>
β
Enable branch policies and required reviewers on main<br>
β
SAST (SonarQube) + SCA (Trivy) + container scanning in every pipeline<br>
β
Implement least-privilege RBAC in Azure DevOps and Kubernetes<br>
β
Enable audit logging in Azure DevOps and Azure Monitor<br>
β
Secret rotation with auto-rotation policies where possible<br>
β
Sign container images (Docker Content Trust / Notary)<br>
β
Network segmentation with NSGs and Network Policies<br>
β
Enable Azure Defender for Containers (runtime protection)
</div>
</div>
<div class="interview-box">
<div class="box-title">π Interview Questions & Answers</div>
<div class="box-content">
<strong>1. Service Principal vs Managed Identity?</strong><br>
SP: app identity with client ID + secret/cert (you manage rotation). MI: Azure-managed identity (no secrets, auto-rotated). Always prefer MI. Use SP only when MI isn't available (e.g., cross-tenant).<br><br>
<strong>2. How do you manage Service Connections?</strong><br>
Project Settings β Service Connections. Types: Azure RM, K8s, Docker, SonarQube. Best practice: use Workload Identity federation, limit to specific pipelines, audit usage regularly.<br><br>
<strong>3. What is Azure Key Vault and pipeline integration?</strong><br>
Centralized secrets management. Integrate via: Variable Groups linked to Key Vault (auto-sync secrets), AzureKeyVault@2 task (fetch at runtime), or K8s CSI driver (mount as volumes in pods).<br><br>
<strong>4. PAT security risks and alternatives?</strong><br>
Risks: can be leaked in logs, shared between users, broad permissions. Alternatives: Managed Identity (Azure resources), SSH keys (Git), OAuth (interactive), Service Principal (automation).<br><br>
<strong>5. Explain RBAC in Azure DevOps.</strong><br>
Role-Based Access Control at org, project, and resource levels. Built-in groups (Admin, Contributor, Reader). Can create custom groups. Best practice: least privilege, use Azure AD groups, regular access reviews.<br><br>
<strong>6. How do you prevent secrets from leaking in pipeline logs?</strong><br>
Mark variables as secret (masked in logs), use Key Vault (variables auto-masked), don't echo secrets in scripts, use ##vso[task.setvariable variable=x;issecret=true], enable credential scanning.<br><br>
<strong>7. What is Workload Identity Federation?</strong><br>
OIDC-based authentication that eliminates secrets entirely. K8s pod gets an OIDC token β exchanges for Azure AD token β accesses Azure resources. No client secret needed. Newest and most secure approach.<br><br>
<strong>8. What is Zero Trust for DevOps?</strong><br>
Apply Zero Trust principles: verify explicitly (authenticate everything), least privilege (minimum permissions), assume breach (encrypt, segment, log). Specific: branch policies, environment approvals, signed artifacts, audit trails.
</div>
</div>
`
},
"mlops": {
concepts: `
<h3>What is MLOps?</h3>
<p>MLOps (Machine Learning Operations) applies DevOps principles to the ML lifecycle: data preparation, model training, evaluation, deployment, and monitoring. It bridges the gap between <strong>data scientists</strong> (experimentation) and <strong>ML engineers</strong> (production).</p>
<div class="pipeline-flow">
<div class="pipeline-stage" style="background: rgba(0,120,212,0.2); color: #0078D4;">Data</div>
<span class="pipeline-arrow">β</span>
<div class="pipeline-stage" style="background: rgba(0,183,195,0.2); color: #00b7c3;">Feature Eng</div>
<span class="pipeline-arrow">β</span>
<div class="pipeline-stage" style="background: rgba(163,113,247,0.2); color: #a371f7;">Train</div>
<span class="pipeline-arrow">β</span>
<div class="pipeline-stage" style="background: rgba(255,107,53,0.2); color: #ff6b35;">Evaluate</div>
<span class="pipeline-arrow">β</span>
<div class="pipeline-stage" style="background: rgba(0,255,136,0.2); color: #00ff88;">Register</div>
<span class="pipeline-arrow">β</span>
<div class="pipeline-stage" style="background: rgba(46,204,113,0.2); color: #2ecc71;">Deploy</div>
<span class="pipeline-arrow">β</span>
<div class="pipeline-stage" style="background: rgba(231,76,60,0.2); color: #e74c3c;">Monitor</div>
</div>
<h3>MLOps Maturity Levels</h3>
<table>
<tr><th>Level</th><th>Name</th><th>Description</th><th>Automation</th></tr>
<tr><td>0</td><td>No MLOps</td><td>Manual notebooks, no versioning, manual deployment</td><td>None</td></tr>
<tr><td>1</td><td>DevOps but no MLOps</td><td>CI/CD for code but not for data or models</td><td>Code only</td></tr>
<tr><td>2</td><td>Automated Training</td><td>Automated training pipeline, model registry, experiment tracking</td><td>Code + Training</td></tr>
<tr><td>3</td><td>Automated Deployment</td><td>CI/CD for models, A/B testing, automated validation</td><td>Code + Training + Deploy</td></tr>
<tr><td>4</td><td>Full MLOps</td><td>Auto-retraining on drift, canary rollouts, full observability</td><td>Everything</td></tr>
</table>
<h3>The Three Pillars of MLOps</h3>
<div class="info-box">
<div class="box-title">π§ Data + Model + Deploy</div>
<div class="box-content">
<strong>1. Data Management:</strong> Data versioning (DVC), data validation (Great Expectations), feature stores (Feast), lineage tracking<br>
<strong>2. Model Management:</strong> Experiment tracking (MLflow), model registry (versioning + staging), reproducibility (environment + hyperparams)<br>
<strong>3. Deployment & Monitoring:</strong> Model serving (batch/real-time), A/B testing, shadow deployments, drift detection, retraining triggers
</div>
</div>
<h3>Data Drift vs Concept Drift vs Model Decay</h3>
<table>
<tr><th>Type</th><th>What Changes</th><th>Detection Method</th><th>Example</th><th>Solution</th></tr>
<tr><td><strong>Data Drift</strong></td><td>Input distribution shifts</td><td>KS test, PSI, JS divergence</td><td>Avg income increases over time</td><td>Retrain on new data</td></tr>
<tr><td><strong>Concept Drift</strong></td><td>InputβOutput relationship changes</td><td>Performance monitoring</td><td>COVID changes purchasing patterns</td><td>Retrain with new labels</td></tr>
<tr><td><strong>Model Decay</strong></td><td>Accuracy degrades gradually</td><td>Accuracy/F1 dashboards</td><td>Model slowly becomes stale</td><td>Scheduled retraining</td></tr>
</table>
<h3>MLOps vs LLMOps</h3>
<table>
<tr><th>Aspect</th><th>Traditional MLOps</th><th>LLMOps</th></tr>
<tr><td>Training</td><td>Custom models from scratch</td><td>Fine-tuning pre-trained models</td></tr>
<tr><td>Evaluation</td><td>Accuracy, F1, AUC</td><td>Human eval, benchmarks, safety tests</td></tr>
<tr><td>Data</td><td>Structured datasets</td><td>Text corpora, RLHF data</td></tr>
<tr><td>Deployment</td><td>Model serving</td><td>Prompt management + model serving</td></tr>
<tr><td>Monitoring</td><td>Data drift, accuracy</td><td>Hallucination, toxicity, latency</td></tr>
<tr><td>Cost</td><td>Compute for training</td><td>Inference cost (token-based billing)</td></tr>
</table>
`,
handson: `
<h3>Azure ML + Azure DevOps Integration</h3>
<div class="code-block">
<span class="comment"># azure-pipelines.yml β MLOps Pipeline</span>
<span class="key">trigger</span>:
<span class="key">branches</span>: { <span class="key">include</span>: [main] }
<span class="key">paths</span>: { <span class="key">include</span>: [src/ml/*, data/*] }
<span class="key">stages</span>:
- <span class="key">stage</span>: DataValidation
<span class="key">jobs</span>:
- <span class="key">job</span>: validate_data
<span class="key">steps</span>:
- <span class="key">script</span>: |
python validate_data.py \\
--input data/train.csv \\
--schema schema.json
python check_data_drift.py \\
--reference data/baseline.csv \\
--current data/train.csv \\
--threshold 0.05
- <span class="key">stage</span>: TrainModel
<span class="key">dependsOn</span>: DataValidation
<span class="key">jobs</span>:
- <span class="key">job</span>: train
<span class="key">steps</span>:
- <span class="key">task</span>: AzureCLI@2
<span class="key">inputs</span>:
<span class="key">azureSubscription</span>: <span class="string">"azure-ml-conn"</span>
<span class="key">scriptType</span>: <span class="string">"bash"</span>
<span class="key">inlineScript</span>: |
az ml job create -f train_job.yml \\
--set inputs.train_data=azureml:train_data:latest
- <span class="key">stage</span>: EvaluateModel
<span class="key">dependsOn</span>: TrainModel
<span class="key">jobs</span>:
- <span class="key">job</span>: evaluate
<span class="key">steps</span>:
- <span class="key">script</span>: |
python evaluate_model.py \\
--model-path outputs/model.pkl \\
--test-data data/test.csv \\
--min-accuracy 0.85
- <span class="key">stage</span>: RegisterModel
<span class="key">dependsOn</span>: EvaluateModel
<span class="key">jobs</span>:
- <span class="key">job</span>: register
<span class="key">steps</span>:
- <span class="key">script</span>: |
az ml model create \\
--name fraud-detector \\
--version $(Build.BuildId) \\
--path outputs/model.pkl \\
--type mlflow_model
- <span class="key">stage</span>: DeployModel
<span class="key">dependsOn</span>: RegisterModel
<span class="key">jobs</span>:
- <span class="key">deployment</span>: deploy
<span class="key">environment</span>: <span class="string">"ml-production"</span>
<span class="key">strategy</span>:
<span class="key">runOnce</span>:
<span class="key">deploy</span>:
<span class="key">steps</span>:
- <span class="key">script</span>: |
az ml online-deployment create \\
-f deployment.yml \\
--set traffic=10 <span class="comment"># Canary: 10% traffic</span>
</div>
<h3>MLflow Experiment Tracking</h3>
<div class="code-block">
<span class="comment"># Python β Track experiments with MLflow</span>
<span class="keyword">import</span> mlflow
<span class="keyword">from</span> sklearn.ensemble <span class="keyword">import</span> RandomForestClassifier
<span class="keyword">from</span> sklearn.metrics <span class="keyword">import</span> accuracy_score, f1_score
mlflow.set_tracking_uri(<span class="string">"azureml://..."</span>)
mlflow.set_experiment(<span class="string">"fraud-detection"</span>)
<span class="keyword">with</span> mlflow.start_run():
<span class="comment"># Log parameters</span>
mlflow.log_param(<span class="string">"learning_rate"</span>, 0.01)
mlflow.log_param(<span class="string">"n_estimators"</span>, 100)
mlflow.log_param(<span class="string">"max_depth"</span>, 10)
<span class="comment"># Train</span>
model = RandomForestClassifier(n_estimators=100)
model.fit(X_train, y_train)
<span class="comment"># Evaluate and log metrics</span>
y_pred = model.predict(X_test)
mlflow.log_metric(<span class="string">"accuracy"</span>, accuracy_score(y_test, y_pred))
mlflow.log_metric(<span class="string">"f1_score"</span>, f1_score(y_test, y_pred))
<span class="comment"># Log model + artifacts</span>
mlflow.sklearn.log_model(model, <span class="string">"model"</span>)
mlflow.log_artifact(<span class="string">"confusion_matrix.png"</span>)
</div>
<h3>Data Drift Detection Script</h3>
<div class="code-block">
<span class="comment"># drift_detector.py β Detect data drift using PSI</span>
<span class="keyword">import</span> numpy <span class="keyword">as</span> np
<span class="keyword">def</span> <span class="key">calculate_psi</span>(baseline, current, bins=10):
<span class="string">"""Population Stability Index"""</span>
baseline_pct = np.histogram(baseline, bins=bins)[0] / len(baseline)
current_pct = np.histogram(current, bins=bins)[0] / len(current)
<span class="comment"># Avoid division by zero</span>
baseline_pct = np.clip(baseline_pct, 0.001, None)
current_pct = np.clip(current_pct, 0.001, None)
psi = np.sum((current_pct - baseline_pct) * np.log(current_pct / baseline_pct))
<span class="keyword">return</span> psi
<span class="comment"># PSI thresholds:</span>
<span class="comment"># < 0.1 β No drift (stable)</span>
<span class="comment"># 0.1-0.2 β Moderate drift (investigate)</span>
<span class="comment"># > 0.2 β Significant drift (retrain!)</span>
</div>
`,
applications: `
<h3>MLOps Tools Ecosystem</h3>
<table>
<tr><th>Category</th><th>Azure</th><th>Open Source</th><th>When to Use</th></tr>
<tr><td>Experiment Tracking</td><td>Azure ML Studio</td><td>MLflow, W&B</td><td>Every ML project</td></tr>
<tr><td>Data Versioning</td><td>Azure ML Datasets</td><td>DVC, LakeFS</td><td>Reproducibility needed</td></tr>
<tr><td>Model Registry</td><td>Azure ML Registry</td><td>MLflow Registry</td><td>Model management</td></tr>
<tr><td>Feature Store</td><td>Azure ML Feature Store</td><td>Feast, Tecton</td><td>Feature reuse across teams</td></tr>
<tr><td>Model Serving</td><td>Azure ML Endpoints</td><td>Seldon, BentoML, TorchServe</td><td>Real-time inference</td></tr>
<tr><td>Monitoring</td><td>Azure ML Monitoring</td><td>Evidently, WhyLabs</td><td>Production drift detection</td></tr>
<tr><td>Pipeline Orchestration</td><td>Azure ML Pipelines</td><td>Kubeflow, Airflow</td><td>Complex training workflows</td></tr>
</table>
<h3>Responsible AI</h3>
<div class="info-box">
<div class="box-title">π€ Microsoft's Responsible AI Principles</div>
<div class="box-content">
<strong>Fairness:</strong> Models should not discriminate (check across demographics)<br>
<strong>Reliability:</strong> Models should work consistently in production<br>
<strong>Privacy:</strong> Data handling must respect privacy regulations (GDPR, CCPA)<br>
<strong>Inclusiveness:</strong> Accessible to all users<br>
<strong>Transparency:</strong> Explainable predictions (SHAP, LIME)<br>
<strong>Accountability:</strong> Clear ownership of model decisions<br><br>
<strong>Azure Tool:</strong> Responsible AI Dashboard (fairness, interpretability, error analysis, causal analysis)
</div>
</div>
<div class="interview-box">
<div class="box-title">π Interview Questions & Answers</div>
<div class="box-content">
<strong>1. What is MLOps and how does it differ from DevOps?</strong><br>
MLOps adds data versioning, model versioning, experiment tracking, drift detection, and continuous training to DevOps. ML systems have more axes of change (code + data + model + hyperparams) making them more complex.<br><br>
<strong>2. Explain MLOps maturity levels.</strong><br>
Level 0: Manual everything. Level 1: CI/CD for code only. Level 2: Automated training pipelines. Level 3: Automated model deployment with validation. Level 4: Full automation including drift-triggered retraining.<br><br>
<strong>3. How do you detect data drift?</strong><br>
Statistical tests: KS test (distribution comparison), PSI (Population Stability Index), JS divergence. Monitor feature distributions over time. PSI > 0.2 = significant drift requiring retraining.<br><br>
<strong>4. What is a model registry?</strong><br>
Central repository for versioned ML models. Tracks: model versions, metrics, lineage (what data/code produced it), stage (staging/production/archived). Enables reproducibility and governance.<br><br>
<strong>5. How do you implement CI/CD for ML in Azure DevOps?</strong><br>
Pipeline stages: data validation β training (az ml job create) β model evaluation (compare to baseline) β register model β deploy to endpoint. Trigger on data changes or code changes.<br><br>
<strong>6. What is a feature store?</strong><br>
Centralized repository for feature definitions and computed feature values. Benefits: feature reuse across teams, consistent features in training vs serving, point-in-time correctness, feature discovery.<br><br>
<strong>7. How do you implement A/B testing for ML models?</strong><br>
Deploy multiple model versions behind same endpoint. Route traffic by percentage (canary: 10/90) or user segments. Compare metrics (accuracy, latency, business KPIs). Gradually shift traffic to winner.<br><br>
<strong>8. What is MLflow and Azure ML integration?</strong><br>
MLflow: open-source platform for experiment tracking, model packaging, deployment. Azure ML natively supports MLflow tracking URI β log experiments from local code to Azure ML. Models logged as MLflow format are auto-deployable.<br><br>
<strong>9. How would you design an auto-retraining pipeline?</strong><br>
Monitor data drift (PSI) and model performance (accuracy). When drift exceeds threshold OR accuracy drops below baseline: trigger training pipeline β evaluate new model β if better, auto-deploy with canary strategy β notify team.<br><br>
<strong>10. What is Responsible AI and why does it matter?</strong><br>
Ethical AI development: fairness (no discrimination), reliability (consistent performance), privacy (data protection), transparency (explainable predictions), accountability (ownership). Azure provides Responsible AI Dashboard for automated checks.
</div>
</div>
`
},
"monitoring": {
concepts: `
<h3>The Three Pillars of Observability</h3>
<div class="info-box">
<div class="box-title">π Logs + Metrics + Traces</div>
<div class="box-content">
<strong>Logs:</strong> Timestamped records of events. Structured logging (JSON) with correlation IDs for tracing across services. Tool: Azure Log Analytics (KQL queries).<br><br>
<strong>Metrics:</strong> Numeric measurements over time (time-series). CPU, memory, request rate, error rate, latency percentiles. Tool: Azure Monitor Metrics, Prometheus.<br><br>
<strong>Traces:</strong> End-to-end request journey across microservices. Shows latency breakdown per service hop. Tool: Application Insights (distributed tracing), Jaeger.
</div>
</div>
<h3>Monitoring Stack in Azure</h3>
<table>
<tr><th>Layer</th><th>What to Monitor</th><th>Azure Tool</th><th>Key Metrics</th></tr>
<tr><td><strong>Infrastructure</strong></td><td>CPU, Memory, Disk, Network</td><td>Azure Monitor</td><td>CPU %, Memory %, Disk IOPS</td></tr>
<tr><td><strong>Application</strong></td><td>Response time, Errors, Throughput</td><td>Application Insights</td><td>P50/P95/P99 latency, error rate</td></tr>
<tr><td><strong>Kubernetes</strong></td><td>Pod health, Node status</td><td>Container Insights</td><td>Pod restarts, OOMKills, node CPU</td></tr>
<tr><td><strong>Pipeline</strong></td><td>Build time, Failure rate</td><td>Azure DevOps Analytics</td><td>DORA metrics</td></tr>
<tr><td><strong>ML Models</strong></td><td>Accuracy, Data drift</td><td>Azure ML Monitoring</td><td>PSI, prediction accuracy</td></tr>
</table>
<h3>SLOs, SLIs, and SLAs</h3>
<table>
<tr><th>Term</th><th>Definition</th><th>Example</th><th>Owner</th></tr>
<tr><td><strong>SLI</strong></td><td>Service Level Indicator (metric)</td><td>Request latency P99</td><td>Engineering</td></tr>
<tr><td><strong>SLO</strong></td><td>Service Level Objective (target)</td><td>P99 latency < 200ms</td><td>Engineering + Product</td></tr>
<tr><td><strong>SLA</strong></td><td>Service Level Agreement (contract)</td><td>99.9% uptime or credits</td><td>Business + Legal</td></tr>
<tr><td><strong>Error Budget</strong></td><td>100% - SLO = room for risk</td><td>99.9% SLO = 43min/month downtime OK</td><td>SRE Team</td></tr>
</table>
<h3>Deployment Verification</h3>
<div class="info-box">
<div class="box-title">β
Post-Deployment Checklist</div>
<div class="box-content">
<strong>1.</strong> AKS β Workloads β Verify pods are Running (not CrashLoopBackOff)<br>
<strong>2.</strong> Services and Ingresses β Get External IP<br>
<strong>3.</strong> Access the app via browser and verify functionality<br>
<strong>4.</strong> Check Application Insights for error spikes<br>
<strong>5.</strong> Verify health check endpoints responding (200 OK)<br>
<strong>6.</strong> Check Container Insights for resource utilization
</div>
</div>
<h3>Incident Management</h3>
<div class="callout warning">
<div class="callout-title">β οΈ Incident Response Framework</div>
<strong>Detect:</strong> Automated alerts (Azure Monitor, PagerDuty)<br>
<strong>Triage:</strong> Classify severity (SEV1 = customer-facing, SEV4 = cosmetic)<br>
<strong>Respond:</strong> Incident commander coordinates. Communicate to stakeholders.<br>
<strong>Mitigate:</strong> Rollback, feature flag, scale up β restore service ASAP<br>
<strong>Review:</strong> Blameless postmortem within 48 hours. Document root cause, timeline, action items.
</div>
<h3>Pipeline Automation</h3>
<div class="callout insight">
<div class="callout-title">π‘ From Manual to Automated</div>
Change <code>trigger: none</code> to <code>trigger: [main]</code> in the YAML pipeline. Then test by creating a new file in Azure Repos β the pipeline should start automatically. Use path filters to trigger only on relevant changes.
</div>
`,
handson: `
<h3>Azure Monitor + Container Insights</h3>
<div class="code-block">
<span class="comment"># Enable Container Insights on AKS</span>
<span class="keyword">az</span> aks enable-addons \\
--resource-group rg-devops \\
--name my-aks-cluster \\
--addons monitoring \\
--workspace-resource-id /subscriptions/.../log-analytics-workspace
<span class="comment"># Create Application Insights</span>
<span class="keyword">az</span> monitor app-insights component create \\
--app bankapp-insights \\
--location eastus \\
--resource-group rg-devops \\
--kind web
</div>
<h3>KQL Queries for Log Analytics</h3>
<div class="code-block">
<span class="comment">// Find all container restarts in last 24 hours</span>
<span class="keyword">KubePodInventory</span>
| <span class="keyword">where</span> TimeGenerated > ago(24h)
| <span class="keyword">where</span> ContainerRestartCount > 0
| <span class="keyword">project</span> TimeGenerated, Namespace, Name, ContainerRestartCount
| <span class="keyword">order by</span> ContainerRestartCount desc
<span class="comment">// Request latency percentiles (Application Insights)</span>
<span class="keyword">requests</span>
| <span class="keyword">where</span> timestamp > ago(1h)
| <span class="keyword">summarize</span>
p50 = percentile(duration, 50),
p95 = percentile(duration, 95),
p99 = percentile(duration, 99),
total = count(),
errors = countif(success == false)
<span class="keyword">by</span> bin(timestamp, 5m)
| <span class="keyword">render</span> timechart
<span class="comment">// Find pods with high CPU usage</span>
<span class="keyword">Perf</span>
| <span class="keyword">where</span> ObjectName == <span class="string">"K8SContainer"</span>
| <span class="keyword">where</span> CounterName == <span class="string">"cpuUsageNanoCores"</span>
| <span class="keyword">summarize</span> avg(CounterValue) by InstanceName
| <span class="keyword">where</span> avg_CounterValue > 500000000 <span class="comment">// > 500m CPU</span>
</div>
<h3>Alerting Rules</h3>
<div class="code-block">
<span class="comment"># Create Azure Monitor Alert for high CPU</span>
<span class="keyword">az</span> monitor metrics alert create \\
--name <span class="string">"high-cpu-alert"</span> \\
--resource-group rg-devops \\
--scopes /subscriptions/.../aks-cluster \\
--condition <span class="string">"avg Percentage CPU > 80"</span> \\
--action /subscriptions/.../action-group \\
--window-size 5m \\
--evaluation-frequency 1m \\
--severity 2
<span class="comment"># Create alert for error rate spike</span>
<span class="keyword">az</span> monitor metrics alert create \\
--name <span class="string">"high-error-rate"</span> \\
--resource-group rg-devops \\
--scopes /subscriptions/.../app-insights \\
--condition <span class="string">"count requests/failed > 10"</span> \\
--window-size 5m \\
--severity 1
</div>
<h3>Pipeline Notifications</h3>
<div class="code-block">
<span class="comment"># Notification stage β runs always (even on failure)</span>
<span class="key">stages</span>:
- <span class="key">stage</span>: Notify
<span class="key">condition</span>: always()
<span class="key">jobs</span>:
- <span class="key">job</span>: send_notification
<span class="key">steps</span>:
- <span class="key">script</span>: |
<span class="keyword">if</span> [ "$(Agent.JobStatus)" == "Succeeded" ]; then
MSG="β
Pipeline PASSED β Build $(Build.BuildId)"
<span class="keyword">else</span>
MSG="β Pipeline FAILED β Build $(Build.BuildId)"
<span class="keyword">fi</span>
<span class="comment"># Send to Microsoft Teams via webhook</span>
curl -H "Content-Type: application/json" \\
-d "{\"text\":\"$MSG\"}" \\
$(TEAMS_WEBHOOK_URL)
</div>
<h3>Grafana Dashboard Setup on AKS</h3>
<div class="code-block">
<span class="comment"># Install Prometheus + Grafana via Helm</span>
<span class="keyword">helm</span> repo add prometheus-community \\
https://prometheus-community.github.io/helm-charts
<span class="keyword">helm</span> install monitoring prometheus-community/kube-prometheus-stack \\
--namespace monitoring \\
--create-namespace \\
--set grafana.adminPassword=<span class="string">"SecurePass123"</span>
<span class="comment"># Access Grafana</span>
<span class="keyword">kubectl</span> port-forward svc/monitoring-grafana 3000:80 -n monitoring
<span class="comment"># Open http://localhost:3000 (admin / SecurePass123)</span>
<span class="comment"># Pre-built dashboards: K8s Cluster, Pod Resources, Node Exporter</span>
</div>
`,
applications: `
<h3>Observability Best Practices</h3>
<div class="info-box">
<div class="box-title">π Production Monitoring Checklist</div>
<div class="box-content">
β
<strong>Application:</strong> Application Insights (latency, errors, throughput)<br>
β
<strong>Infrastructure:</strong> Container Insights (CPU, memory, disk per pod/node)<br>
β
<strong>Alerting:</strong> Severity-based alerts (SEV1 β PagerDuty, SEV3 β Teams)<br>
β
<strong>Dashboards:</strong> Grafana or Azure Workbooks for team-specific views<br>
β
<strong>Logging:</strong> Structured JSON logs with correlation IDs<br>
β
<strong>Tracing:</strong> Distributed tracing across microservices<br>
β
<strong>SLOs:</strong> Defined for critical services with error budgets<br>
β
<strong>Runbooks:</strong> Automated remediation for common issues<br>
β
<strong>Postmortems:</strong> Blameless review within 48 hours of incidents
</div>
</div>
<h3>Golden Signals of Monitoring</h3>
<table>
<tr><th>Signal</th><th>What to Measure</th><th>Alert Threshold</th></tr>
<tr><td><strong>Latency</strong></td><td>P50, P95, P99 response times</td><td>P99 > 500ms</td></tr>
<tr><td><strong>Traffic</strong></td><td>Requests per second</td><td>Sudden drop > 50%</td></tr>
<tr><td><strong>Errors</strong></td><td>HTTP 5xx rate, exception rate</td><td>Error rate > 1%</td></tr>
<tr><td><strong>Saturation</strong></td><td>CPU, memory, queue depth</td><td>CPU > 80%, Memory > 85%</td></tr>
</table>
<div class="interview-box">
<div class="box-title">π Interview Questions & Answers</div>
<div class="box-content">
<strong>1. How do you verify a deployment in AKS?</strong><br>
Check pod status (kubectl get pods), verify service endpoints, test health check URLs, check Application Insights for error spikes, verify Container Insights for resource usage. Use deployment jobs with health checks.<br><br>
<strong>2. What are the three pillars of observability?</strong><br>
Logs (what happened β event records), Metrics (how much β time-series numbers), Traces (where β request journey across services). All three together provide complete system understanding.<br><br>
<strong>3. What are SLOs, SLIs, SLAs?</strong><br>
SLI: the metric you measure (P99 latency). SLO: the target you set (P99 < 200ms). SLA: the contract with customers (99.9% uptime or credits). Error budget = 100% - SLO = acceptable downtime.<br><br>
<strong>4. What are the Golden Signals?</strong><br>
Google SRE's four key metrics: Latency (how fast), Traffic (how much), Errors (how often it fails), Saturation (how full). Every service should be monitored on these four signals.<br><br>
<strong>5. What is KQL and how is it used?</strong><br>
Kusto Query Language β used in Azure Log Analytics and Application Insights. SQL-like syntax for querying logs and metrics. Key operators: where, summarize, project, render. Essential for building dashboards and alerts.<br><br>
<strong>6. How do you set up alerting?</strong><br>
Azure Monitor β Alerts β Metric/log-based rules with severity levels. Action groups define notification targets (email, SMS, Teams, PagerDuty, Azure Functions). Use severity 1-4 for priority routing.<br><br>
<strong>7. Prometheus + Grafana vs Azure Monitor?</strong><br>
Prometheus+Grafana: open-source, portable, highly customizable, runs in-cluster. Azure Monitor: managed service, integrated with Azure, less ops burden, supports multi-cloud via Azure Arc. Many teams use both.<br><br>
<strong>8. What is a blameless postmortem?</strong><br>
After-incident review focused on systems and processes, not individuals. Documents: timeline, root cause, impact, what went well, what didn't, action items. Goal: organizational learning and system improvement.<br><br>
<strong>9. How do you track DORA metrics?</strong><br>
Deployment Frequency: pipeline run count. Lead Time: commit timestamp to deploy timestamp. Change Failure Rate: failed deploys / total deploys. MTTR: time between incident detection and resolution. Azure DevOps Analytics provides these.<br><br>
<strong>10. How would you set up monitoring for an ML model?</strong><br>
Monitor: prediction latency, request volume, prediction distribution, data drift (PSI), model accuracy on labeled samples. Alert on: drift > threshold, accuracy drop, latency spike. Auto-trigger retraining pipeline on significant drift.
</div>
</div>
`
}
};
function createModuleHTML(module) {
const content = MODULE_CONTENT[module.id] || {};
return `
<div class="module" id="${module.id}-module">
<button class="btn-back" onclick="switchTo('dashboard')">β Back to Dashboard</button>
<header>
<h1>${module.icon} ${module.title}</h1>
<p class="subtitle">${module.description}</p>
</header>
<div class="tabs">
<button class="tab-btn active" onclick="switchTab(event, '${module.id}-concepts')">π Key Concepts</button>
<button class="tab-btn" onclick="switchTab(event, '${module.id}-handson')">π§ Hands-On / YAML</button>
<button class="tab-btn" onclick="switchTab(event, '${module.id}-applications')">π― Applications & Interview</button>
</div>
<div id="${module.id}-concepts" class="tab active">
<div class="section">
<h2>π Key Concepts</h2>
${content.concepts || '<p>Content loading...</p>'}
</div>
</div>
<div id="${module.id}-handson" class="tab">
<div class="section">
<h2>π§ Hands-On / YAML</h2>
${content.handson || '<p>Content loading...</p>'}
</div>
</div>
<div id="${module.id}-applications" class="tab">
<div class="section">
<h2>π― Applications & Interview Questions</h2>
${content.applications || '<p>Content loading...</p>'}
</div>
</div>
</div>
`;
}
function initDashboard() {
const grid = document.getElementById("modulesGrid");
const container = document.getElementById("modulesContainer");
modules.forEach((module) => {
const card = document.createElement("div");
card.className = "card";
card.style.borderColor = module.color;
card.onclick = () => switchTo(module.id + "-module");
card.innerHTML = `
<div class="card-icon">${module.icon}</div>
<h3>${module.title}</h3>
<p>${module.description}</p>
<span class="category-label">${module.category}</span>
`;
grid.appendChild(card);
container.innerHTML += createModuleHTML(module);
});
}
function switchTo(target) {
document.querySelectorAll('.dashboard, .module').forEach(el => el.classList.remove('active'));
const elem = document.getElementById(target);
if (elem) { elem.classList.add('active'); window.scrollTo(0, 0); }
}
function switchTab(e, tabId) {
const module = e.target.closest('.module');
if (!module) return;
module.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));
module.querySelectorAll('.tab-btn').forEach(b => b.classList.remove('active'));
const tab = document.getElementById(tabId);
if (tab) tab.classList.add('active');
e.target.classList.add('active');
}
initDashboard();
</script>
</body>
</html> |