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
|
---
stage: Systems
group: Distribution
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
# Reference architecture: Up to 500 RPS or 25,000 users
DETAILS:
**Tier:** Premium, Ultimate
**Offering:** Self-managed
This page describes the GitLab reference architecture designed to target a peak load of 500 requests per second (RPS) - The typical peak load of up to 25,000 users, both manual and automated, based on real data.
For a full list of reference architectures, see
[Available reference architectures](index.md#available-reference-architectures).
NOTE:
Before deploying this architecture it's recommended to read through the [main documentation](index.md) first,
specifically the [Before you start](index.md#before-you-start) and [Deciding which architecture to use](index.md#deciding-which-architecture-to-start-with) sections.
> - **Target load:** API: 500 RPS, Web: 50 RPS, Git (Pull): 50 RPS, Git (Push): 10 RPS
> - **High Availability:** Yes ([Praefect](#configure-praefect-postgresql) needs a third-party PostgreSQL solution for HA)
> - **Cost calculator template:** [See cost calculator templates section](index.md#cost-calculator-templates)
> - **Cloud Native Hybrid Alternative:** [Yes](#cloud-native-hybrid-reference-architecture-with-helm-charts-alternative)
> - **Unsure which Reference Architecture to use?** [Go to this guide for more info](index.md#deciding-which-architecture-to-start-with)
| Service | Nodes | Configuration | GCP | AWS | Azure |
|------------------------------------------|-------|-------------------------|------------------|--------------|-----------|
| External load balancer<sup>3</sup> | 1 | 8 vCPU, 7.2 GB memory | `n1-highcpu-8` | `c5n.2xlarge` | `F8s v2` |
| Consul<sup>1</sup> | 3 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` | `F2s v2` |
| PostgreSQL<sup>1</sup> | 3 | 16 vCPU, 60 GB memory | `n1-standard-16` | `m5.4xlarge` | `D16s v3` |
| PgBouncer<sup>1</sup> | 3 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` | `F2s v2` |
| Internal load balancer<sup>3</sup> | 1 | 8 vCPU, 7.2 GB memory | `n1-highcpu-8` | `c5n.2xlarge` | `F8s v2` |
| Redis/Sentinel - Cache<sup>2</sup> | 3 | 4 vCPU, 15 GB memory | `n1-standard-4` | `m5.xlarge` | `D4s v3` |
| Redis/Sentinel - Persistent<sup>2</sup> | 3 | 4 vCPU, 15 GB memory | `n1-standard-4` | `m5.xlarge` | `D4s v3` |
| Gitaly<sup>5</sup> | 3 | 32 vCPU, 120 GB memory<sup>6</sup> | `n1-standard-32` | `m5.8xlarge` | `D32s v3` |
| Praefect<sup>5</sup> | 3 | 4 vCPU, 3.6 GB memory | `n1-highcpu-4` | `c5.xlarge` | `F4s v2` |
| Praefect PostgreSQL<sup>1</sup> | 1+ | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` | `F2s v2` |
| Sidekiq<sup>7</sup> | 4 | 4 vCPU, 15 GB memory | `n1-standard-4` | `m5.xlarge` | `D4s v3` |
| GitLab Rails<sup>7</sup> | 5 | 32 vCPU, 28.8 GB memory | `n1-highcpu-32` | `c5.9xlarge` | `F32s v2` |
| Monitoring node | 1 | 4 vCPU, 3.6 GB memory | `n1-highcpu-4` | `c5.xlarge` | `F4s v2` |
| Object storage<sup>4</sup> | - | - | - | - | - |
**Footnotes:**
<!-- Disable ordered list rule https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md029---ordered-list-item-prefix -->
<!-- markdownlint-disable MD029 -->
1. Can be optionally run on reputable third-party external PaaS PostgreSQL solutions. See [Provide your own PostgreSQL instance](#provide-your-own-postgresql-instance) for more information.
2. Can be optionally run on reputable third-party external PaaS Redis solutions. See [Provide your own Redis instances](#provide-your-own-redis-instances) for more information.
- Redis is primarily single threaded and doesn't significantly benefit from an increase in CPU cores. For this size of architecture it's strongly recommended having separate Cache and Persistent instances as specified to achieve optimum performance.
3. Recommended to be run with a reputable third-party load balancer or service (LB PaaS) which can provide HA capabilities.
Also, the sizing depends on selected Load Balancer and additional factors such as Network Bandwidth. Refer to [Load Balancers](index.md#load-balancers) for more information.
4. Should be run on reputable Cloud Provider or Self Managed solutions. See [Configure the object storage](#configure-the-object-storage) for more information.
5. Gitaly Cluster provides the benefits of fault tolerance, but comes with additional complexity of setup and management.
Review the existing [technical limitations and considerations before deploying Gitaly Cluster](../gitaly/index.md#before-deploying-gitaly-cluster). If you want sharded Gitaly, use the same specs listed above for `Gitaly`.
6. Gitaly specifications are based on high percentiles of both usage patterns and repository sizes in good health.
However, if you have [large monorepos](index.md#large-monorepos) (larger than several gigabytes) or [additional workloads](index.md#additional-workloads) these can *significantly* impact Git and Gitaly performance and further adjustments will likely be required.
6. Can be placed in Auto Scaling Groups (ASGs) as the component doesn't store any [stateful data](index.md#autoscaling-of-stateful-nodes).
However, [Cloud Native Hybrid setups](#cloud-native-hybrid-reference-architecture-with-helm-charts-alternative) are generally preferred as certain components
such as like [migrations](#gitlab-rails-post-configuration) and [Mailroom](../incoming_email.md) can only be run on one node, which is handled better in Kubernetes.
<!-- markdownlint-enable MD029 -->
NOTE:
For all PaaS solutions that involve configuring instances, it's recommended to implement a minimum of three nodes in three different availability zones to align with resilient cloud architecture practices.
```plantuml
@startuml 25k
skinparam linetype ortho
card "**External Load Balancer**" as elb #6a9be7
card "**Internal Load Balancer**" as ilb #9370DB
together {
collections "**GitLab Rails** x5" as gitlab #32CD32
collections "**Sidekiq** x4" as sidekiq #ff8dd1
}
together {
card "**Prometheus**" as monitor #7FFFD4
collections "**Consul** x3" as consul #e76a9b
}
card "Gitaly Cluster" as gitaly_cluster {
collections "**Praefect** x3" as praefect #FF8C00
collections "**Gitaly** x3" as gitaly #FF8C00
card "**Praefect PostgreSQL***\n//Non fault-tolerant//" as praefect_postgres #FF8C00
praefect -[#FF8C00]-> gitaly
praefect -[#FF8C00]> praefect_postgres
}
card "Database" as database {
collections "**PGBouncer** x3" as pgbouncer #4EA7FF
card "**PostgreSQL** //Primary//" as postgres_primary #4EA7FF
collections "**PostgreSQL** //Secondary// x2" as postgres_secondary #4EA7FF
pgbouncer -[#4EA7FF]-> postgres_primary
postgres_primary .[#4EA7FF]> postgres_secondary
}
card "redis" as redis {
collections "**Redis Persistent** x3" as redis_persistent #FF6347
collections "**Redis Cache** x3" as redis_cache #FF6347
redis_cache -[hidden]-> redis_persistent
}
cloud "**Object Storage**" as object_storage #white
elb -[#6a9be7]-> gitlab
elb -[#6a9be7,norank]--> monitor
gitlab -[#32CD32,norank]--> ilb
gitlab -[#32CD32]r-> object_storage
gitlab -[#32CD32]----> redis
gitlab .[#32CD32]----> database
gitlab -[hidden]-> monitor
gitlab -[hidden]-> consul
sidekiq -[#ff8dd1,norank]--> ilb
sidekiq -[#ff8dd1]r-> object_storage
sidekiq -[#ff8dd1]----> redis
sidekiq .[#ff8dd1]----> database
sidekiq -[hidden]-> monitor
sidekiq -[hidden]-> consul
ilb -[#9370DB]--> gitaly_cluster
ilb -[#9370DB]--> database
ilb -[hidden]--> redis
ilb -[hidden]u-> consul
ilb -[hidden]u-> monitor
consul .[#e76a9b]u-> gitlab
consul .[#e76a9b]u-> sidekiq
consul .[#e76a9b]r-> monitor
consul .[#e76a9b]-> database
consul .[#e76a9b]-> gitaly_cluster
consul .[#e76a9b,norank]--> redis
monitor .[#7FFFD4]u-> gitlab
monitor .[#7FFFD4]u-> sidekiq
monitor .[#7FFFD4]> consul
monitor .[#7FFFD4]-> database
monitor .[#7FFFD4]-> gitaly_cluster
monitor .[#7FFFD4,norank]--> redis
monitor .[#7FFFD4]> ilb
monitor .[#7FFFD4,norank]u--> elb
@enduml
```
## Requirements
Before starting, see the [requirements](index.md#requirements) for reference architectures.
## Testing methodology
The 25k architecture is designed to cover a large majority of workflows and is regularly
[smoke and performance tested](index.md#validation-and-test-results) by the Test Platform team
against the following endpoint throughput targets:
- API: 500 RPS
- Web: 50 RPS
- Git (Pull): 50 RPS
- Git (Push): 10 RPS
The above targets were selected based on real customer data of total environmental loads corresponding to the user count,
including CI and other workloads.
If you have metrics to suggest that you have regularly higher throughput against the above endpoint targets, [large monorepos](index.md#large-monorepos)
or notable [additional workloads](index.md#additional-workloads) these can notably impact the performance environment and [further adjustments may be required](index.md#scaling-an-environment).
If this applies to you, we strongly recommended referring to the linked documentation and reaching out to your [Customer Success Manager](https://handbook.gitlab.com/job-families/sales/customer-success-management/) or our [Support team](https://about.gitlab.com/support/) for further guidance.
Testing is done regularly by using the [GitLab Performance Tool (GPT)](https://gitlab.com/gitlab-org/quality/performance) and its dataset, which is available for anyone to use.
The results of this testing are [available publicly on the GPT wiki](https://gitlab.com/gitlab-org/quality/performance/-/wikis/Benchmarks/Latest). For more information on our testing strategy [refer to this section of the documentation](index.md#validation-and-test-results).
The load balancers used for testing were HAProxy for Linux package environments or equivalent Cloud Provider services with NGINX Ingress for Cloud Native Hybrids. These selections do not represent a specific requirement or recommendation as most [reputable load balancers are expected to work](#configure-the-external-load-balancer).
## Set up components
To set up GitLab and its components to accommodate up to 500 RPS or 25,000 users:
1. [Configure the external load balancer](#configure-the-external-load-balancer)
to handle the load balancing of the GitLab application services nodes.
1. [Configure the internal load balancer](#configure-the-internal-load-balancer)
to handle the load balancing of GitLab application internal connections.
1. [Configure Consul](#configure-consul) for service discovery and health checking.
1. [Configure PostgreSQL](#configure-postgresql), the database for GitLab.
1. [Configure PgBouncer](#configure-pgbouncer) for database connection pooling and management.
1. [Configure Redis](#configure-redis), which stores session data, temporary
cache information, and background job queues.
1. [Configure Gitaly Cluster](#configure-gitaly-cluster),
provides access to the Git repositories.
1. [Configure Sidekiq](#configure-sidekiq) for background job processing.
1. [Configure the main GitLab Rails application](#configure-gitlab-rails)
to run Puma, Workhorse, GitLab Shell, and to serve all frontend
requests (which include UI, API, and Git over HTTP/SSH).
1. [Configure Prometheus](#configure-prometheus) to monitor your GitLab
environment.
1. [Configure the object storage](#configure-the-object-storage)
used for shared data objects.
1. [Configure advanced search](#configure-advanced-search) (optional) for faster,
more advanced code search across your entire GitLab instance.
The servers start on the same 10.6.0.0/24 private network range, and can
connect to each other freely on these addresses.
The following list includes descriptions of each server and its assigned IP:
- `10.6.0.10`: External Load Balancer
- `10.6.0.11`: Consul 1
- `10.6.0.12`: Consul 2
- `10.6.0.13`: Consul 3
- `10.6.0.21`: PostgreSQL primary
- `10.6.0.22`: PostgreSQL secondary 1
- `10.6.0.23`: PostgreSQL secondary 2
- `10.6.0.31`: PgBouncer 1
- `10.6.0.32`: PgBouncer 2
- `10.6.0.33`: PgBouncer 3
- `10.6.0.40`: Internal Load Balancer
- `10.6.0.51`: Redis - Cache Primary
- `10.6.0.52`: Redis - Cache Replica 1
- `10.6.0.53`: Redis - Cache Replica 2
- `10.6.0.61`: Redis - Persistent Primary
- `10.6.0.62`: Redis - Persistent Replica 1
- `10.6.0.63`: Redis - Persistent Replica 2
- `10.6.0.91`: Gitaly 1
- `10.6.0.92`: Gitaly 2
- `10.6.0.93`: Gitaly 3
- `10.6.0.131`: Praefect 1
- `10.6.0.132`: Praefect 2
- `10.6.0.133`: Praefect 3
- `10.6.0.141`: Praefect PostgreSQL 1 (non HA)
- `10.6.0.101`: Sidekiq 1
- `10.6.0.102`: Sidekiq 2
- `10.6.0.103`: Sidekiq 3
- `10.6.0.104`: Sidekiq 4
- `10.6.0.111`: GitLab application 1
- `10.6.0.112`: GitLab application 2
- `10.6.0.113`: GitLab application 3
- `10.6.0.114`: GitLab application 4
- `10.6.0.115`: GitLab application 5
- `10.6.0.151`: Prometheus
## Configure the external load balancer
In a multi-node GitLab configuration, you'll need an external load balancer to route
traffic to the application servers.
The specifics on which load balancer to use, or its exact configuration
is beyond the scope of GitLab documentation but refer to [Load Balancers](index.md) for more information around
general requirements. This section will focus on the specifics of
what to configure for your load balancer of choice.
### Readiness checks
Ensure the external load balancer only routes to working services with built
in monitoring endpoints. The [readiness checks](../monitoring/health_check.md)
all require [additional configuration](../monitoring/ip_allowlist.md)
on the nodes being checked, otherwise, the external load balancer will not be able to
connect.
### Ports
The basic ports to be used are shown in the table below.
| LB Port | Backend Port | Protocol |
| ------- | ------------ | ------------------------ |
| 80 | 80 | HTTP (*1*) |
| 443 | 443 | TCP or HTTPS (*1*) (*2*) |
| 22 | 22 | TCP |
- (*1*): [Web terminal](../../ci/environments/index.md#web-terminals-deprecated) support requires
your load balancer to correctly handle WebSocket connections. When using
HTTP or HTTPS proxying, this means your load balancer must be configured
to pass through the `Connection` and `Upgrade` hop-by-hop headers. See the
[web terminal](../integration/terminal.md) integration guide for
more details.
- (*2*): When using HTTPS protocol for port 443, you will need to add an SSL
certificate to the load balancers. If you wish to terminate SSL at the
GitLab application server instead, use TCP protocol.
If you're using GitLab Pages with custom domain support you will need some
additional port configurations.
GitLab Pages requires a separate virtual IP address. Configure DNS to point the
`pages_external_url` from `/etc/gitlab/gitlab.rb` at the new virtual IP address. See the
[GitLab Pages documentation](../pages/index.md) for more information.
| LB Port | Backend Port | Protocol |
| ------- | ------------- | --------- |
| 80 | Varies (*1*) | HTTP |
| 443 | Varies (*1*) | TCP (*2*) |
- (*1*): The backend port for GitLab Pages depends on the
`gitlab_pages['external_http']` and `gitlab_pages['external_https']`
setting. See [GitLab Pages documentation](../pages/index.md) for more details.
- (*2*): Port 443 for GitLab Pages should always use the TCP protocol. Users can
configure custom domains with custom SSL, which would not be possible
if SSL was terminated at the load balancer.
#### Alternate SSH Port
Some organizations have policies against opening SSH port 22. In this case,
it may be helpful to configure an alternate SSH hostname that allows users
to use SSH on port 443. An alternate SSH hostname will require a new virtual IP address
compared to the other GitLab HTTP configuration above.
Configure DNS for an alternate SSH hostname such as `altssh.gitlab.example.com`.
| LB Port | Backend Port | Protocol |
| ------- | ------------ | -------- |
| 443 | 22 | TCP |
### SSL
The next question is how you will handle SSL in your environment.
There are several different options:
- [The application node terminates SSL](#application-node-terminates-ssl).
- [The load balancer terminates SSL without backend SSL](#load-balancer-terminates-ssl-without-backend-ssl)
and communication is not secure between the load balancer and the application node.
- [The load balancer terminates SSL with backend SSL](#load-balancer-terminates-ssl-with-backend-ssl)
and communication is *secure* between the load balancer and the application node.
#### Application node terminates SSL
Configure your load balancer to pass connections on port 443 as `TCP` rather
than `HTTP(S)` protocol. This will pass the connection to the application node's
NGINX service untouched. NGINX will have the SSL certificate and listen on port 443.
See the [HTTPS documentation](https://docs.gitlab.com/omnibus/settings/ssl/index.html)
for details on managing SSL certificates and configuring NGINX.
#### Load balancer terminates SSL without backend SSL
Configure your load balancer to use the `HTTP(S)` protocol rather than `TCP`.
The load balancer will then be responsible for managing SSL certificates and
terminating SSL.
Since communication between the load balancer and GitLab will not be secure,
there is some additional configuration needed. See the
[proxied SSL documentation](https://docs.gitlab.com/omnibus/settings/ssl/index.html#configure-a-reverse-proxy-or-load-balancer-ssl-termination)
for details.
#### Load balancer terminates SSL with backend SSL
Configure your load balancers to use the 'HTTP(S)' protocol rather than 'TCP'.
The load balancers will be responsible for managing SSL certificates that
end users will see.
Traffic will also be secure between the load balancers and NGINX in this
scenario. There is no need to add configuration for proxied SSL since the
connection will be secure all the way. However, configuration will need to be
added to GitLab to configure SSL certificates. See
the [HTTPS documentation](https://docs.gitlab.com/omnibus/settings/ssl/index.html)
for details on managing SSL certificates and configuring NGINX.
<div align="right">
<a type="button" class="btn btn-default" href="#set-up-components">
Back to set up components <i class="fa fa-angle-double-up" aria-hidden="true"></i>
</a>
</div>
## Configure the internal load balancer
The Internal Load Balancer is used to balance any internal connections the GitLab environment requires
such as connections to [PgBouncer](#configure-pgbouncer) and [Praefect](#configure-praefect) (Gitaly Cluster).
It's a separate node from the External Load Balancer and shouldn't have any access externally.
The following IP will be used as an example:
- `10.6.0.40`: Internal Load Balancer
Here's how you could do it with [HAProxy](https://www.haproxy.org/):
```plaintext
global
log /dev/log local0
log localhost local1 notice
log stdout format raw local0
defaults
log global
default-server inter 10s fall 3 rise 2
balance leastconn
frontend internal-pgbouncer-tcp-in
bind *:6432
mode tcp
option tcplog
default_backend pgbouncer
frontend internal-praefect-tcp-in
bind *:2305
mode tcp
option tcplog
option clitcpka
default_backend praefect
backend pgbouncer
mode tcp
option tcp-check
server pgbouncer1 10.6.0.31:6432 check
server pgbouncer2 10.6.0.32:6432 check
server pgbouncer3 10.6.0.33:6432 check
backend praefect
mode tcp
option tcp-check
option srvtcpka
server praefect1 10.6.0.131:2305 check
server praefect2 10.6.0.132:2305 check
server praefect3 10.6.0.133:2305 check
```
Refer to your preferred Load Balancer's documentation for further guidance.
<div align="right">
<a type="button" class="btn btn-default" href="#set-up-components">
Back to set up components <i class="fa fa-angle-double-up" aria-hidden="true"></i>
</a>
</div>
<div align="right">
<a type="button" class="btn btn-default" href="#set-up-components">
Back to set up components <i class="fa fa-angle-double-up" aria-hidden="true"></i>
</a>
</div>
## Configure Consul
Next, we set up the Consul servers.
NOTE:
Consul must be deployed in an odd number of 3 nodes or more. This is to ensure the nodes can take votes as part of a quorum.
The following IPs will be used as an example:
- `10.6.0.11`: Consul 1
- `10.6.0.12`: Consul 2
- `10.6.0.13`: Consul 3
To configure Consul:
1. SSH in to the server that will host Consul.
1. [Download and install](https://about.gitlab.com/install/) the Linux
package of your choice. Be sure to both follow _only_ installation steps 1 and 2
on the page, and to select the correct Linux package, with the same version
and type (Community or Enterprise editions) as your current install.
1. Edit `/etc/gitlab/gitlab.rb` and add the contents:
```ruby
roles(['consul_role'])
## Enable service discovery for Prometheus
consul['monitoring_service_discovery'] = true
## The IPs of the Consul server nodes
## You can also use FQDNs and intermix them with IPs
consul['configuration'] = {
server: true,
retry_join: %w(10.6.0.11 10.6.0.12 10.6.0.13),
}
# Set the network addresses that the exporters will listen on
node_exporter['listen_address'] = '0.0.0.0:9100'
# Prevent database migrations from running on upgrade automatically
gitlab_rails['auto_migrate'] = false
```
1. Copy the `/etc/gitlab/gitlab-secrets.json` file from the first Linux package node you configured and add or replace
the file of the same name on this server. If this is the first Linux package node you are configuring then you can skip this step.
1. [Reconfigure GitLab](../restart_gitlab.md#reconfigure-a-linux-package-installation) for the changes to take effect.
1. Go through the steps again for all the other Consul nodes, and
make sure you set up the correct IPs.
A Consul leader is _elected_ when the provisioning of the third Consul server is
complete. Viewing the Consul logs `sudo gitlab-ctl tail consul` displays
`...[INFO] consul: New leader elected: ...`.
You can list the current Consul members (server, client):
```shell
sudo /opt/gitlab/embedded/bin/consul members
```
You can verify the GitLab services are running:
```shell
sudo gitlab-ctl status
```
The output should be similar to the following:
```plaintext
run: consul: (pid 30074) 76834s; run: log: (pid 29740) 76844s
run: logrotate: (pid 30925) 3041s; run: log: (pid 29649) 76861s
run: node-exporter: (pid 30093) 76833s; run: log: (pid 29663) 76855s
```
<div align="right">
<a type="button" class="btn btn-default" href="#set-up-components">
Back to set up components <i class="fa fa-angle-double-up" aria-hidden="true"></i>
</a>
</div>
## Configure PostgreSQL
In this section, you'll be guided through configuring a highly available PostgreSQL
cluster to be used with GitLab.
### Provide your own PostgreSQL instance
You can optionally use a [third party external service for PostgreSQL](../../administration/postgresql/external.md).
A reputable provider or solution should be used for this. [Google Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal)
and [Amazon RDS](https://aws.amazon.com/rds/) are known to work. However, Amazon Aurora is **incompatible** with load balancing enabled by default from
[14.4.0](https://docs.gitlab.com/17.3/ee/update/versions/gitlab_14_changes.html#1440).
See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information.
If you use a third party external service:
1. The HA Linux package PostgreSQL setup encompasses PostgreSQL, PgBouncer and Consul. These components would no longer be required when using a third party external service.
1. Set up PostgreSQL according to the
[database requirements document](../../install/requirements.md#postgresql).
1. Set up a `gitlab` username with a password of your choice. The `gitlab` user
needs privileges to create the `gitlabhq_production` database.
1. Configure the GitLab application servers with the appropriate details.
This step is covered in [Configuring the GitLab Rails application](#configure-gitlab-rails).
1. The number of nodes required to achieve HA may differ depending on the service compared to the Linux package and doesn't need to match accordingly.
1. However, if [Database Load Balancing](../postgresql/database_load_balancing.md) via Read Replicas is desired for further improved performance it's recommended to follow the node count for the Reference Architecture.
### Standalone PostgreSQL using the Linux package
The recommended Linux package configuration for a PostgreSQL cluster with
replication and failover requires:
- A minimum of three PostgreSQL nodes.
- A minimum of three Consul server nodes.
- A minimum of three PgBouncer nodes that track and handle primary database reads and writes.
- An [internal load balancer](#configure-the-internal-load-balancer) (TCP) to balance requests between the PgBouncer nodes.
- [Database Load Balancing](../postgresql/database_load_balancing.md) enabled.
A local PgBouncer service to be configured on each PostgreSQL node. This is separate from the main PgBouncer cluster that tracks the primary.
The following IPs are used as an example:
- `10.6.0.21`: PostgreSQL primary
- `10.6.0.22`: PostgreSQL secondary 1
- `10.6.0.23`: PostgreSQL secondary 2
First, make sure to [install](https://about.gitlab.com/install/)
the Linux GitLab package **on each node**. Following the steps,
install the necessary dependencies from step 1, and add the
GitLab package repository from step 2. When installing GitLab
in the second step, do not supply the `EXTERNAL_URL` value.
#### PostgreSQL nodes
1. SSH in to one of the PostgreSQL nodes.
1. Generate a password hash for the PostgreSQL username/password pair. This assumes you will use the default
username of `gitlab` (recommended). The command will request a password
and confirmation. Use the value that is output by this command in the next
step as the value of `<postgresql_password_hash>`:
```shell
sudo gitlab-ctl pg-password-md5 gitlab
```
1. Generate a password hash for the PgBouncer username/password pair. This assumes you will use the default
username of `pgbouncer` (recommended). The command will request a password
and confirmation. Use the value that is output by this command in the next
step as the value of `<pgbouncer_password_hash>`:
```shell
sudo gitlab-ctl pg-password-md5 pgbouncer
```
1. Generate a password hash for the PostgreSQL replication username/password pair. This assumes you will use the default
username of `gitlab_replicator` (recommended). The command will request a password
and a confirmation. Use the value that is output by this command in the next step
as the value of `<postgresql_replication_password_hash>`:
```shell
sudo gitlab-ctl pg-password-md5 gitlab_replicator
```
1. Generate a password hash for the Consul database username/password pair. This assumes you will use the default
username of `gitlab-consul` (recommended). The command will request a password
and confirmation. Use the value that is output by this command in the next
step as the value of `<consul_password_hash>`:
```shell
sudo gitlab-ctl pg-password-md5 gitlab-consul
```
1. On every database node, edit `/etc/gitlab/gitlab.rb` replacing values noted in the `# START user configuration` section:
```ruby
# Disable all components except Patroni, PgBouncer and Consul
roles(['patroni_role', 'pgbouncer_role'])
# PostgreSQL configuration
postgresql['listen_address'] = '0.0.0.0'
# Sets `max_replication_slots` to double the number of database nodes.
# Patroni uses one extra slot per node when initiating the replication.
patroni['postgresql']['max_replication_slots'] = 6
# Set `max_wal_senders` to one more than the number of replication slots in the cluster.
# This is used to prevent replication from using up all of the
# available database connections.
patroni['postgresql']['max_wal_senders'] = 7
# Prevent database migrations from running on upgrade automatically
gitlab_rails['auto_migrate'] = false
# Configure the Consul agent
consul['services'] = %w(postgresql)
## Enable service discovery for Prometheus
consul['monitoring_service_discovery'] = true
# START user configuration
# Please set the real values as explained in Required Information section
#
# Replace PGBOUNCER_PASSWORD_HASH with a generated md5 value
postgresql['pgbouncer_user_password'] = '<pgbouncer_password_hash>'
# Replace POSTGRESQL_REPLICATION_PASSWORD_HASH with a generated md5 value
postgresql['sql_replication_password'] = '<postgresql_replication_password_hash>'
# Replace POSTGRESQL_PASSWORD_HASH with a generated md5 value
postgresql['sql_user_password'] = '<postgresql_password_hash>'
# Set up basic authentication for the Patroni API (use the same username/password in all nodes).
patroni['username'] = '<patroni_api_username>'
patroni['password'] = '<patroni_api_password>'
# Replace 10.6.0.0/24 with Network Address
postgresql['trust_auth_cidr_addresses'] = %w(10.6.0.0/24 127.0.0.1/32)
# Local PgBouncer service for Database Load Balancing
pgbouncer['databases'] = {
gitlabhq_production: {
host: "127.0.0.1",
user: "pgbouncer",
password: '<pgbouncer_password_hash>'
}
}
# Set the network addresses that the exporters will listen on for monitoring
node_exporter['listen_address'] = '0.0.0.0:9100'
postgres_exporter['listen_address'] = '0.0.0.0:9187'
## The IPs of the Consul server nodes
## You can also use FQDNs and intermix them with IPs
consul['configuration'] = {
retry_join: %w(10.6.0.11 10.6.0.12 10.6.0.13),
}
#
# END user configuration
```
PostgreSQL, with Patroni managing its failover, will default to use `pg_rewind` by default to handle conflicts.
Like most failover handling methods, this has a small chance of leading to data loss.
For more information, see the various [Patroni replication methods](../postgresql/replication_and_failover.md#selecting-the-appropriate-patroni-replication-method).
1. Copy the `/etc/gitlab/gitlab-secrets.json` file from the first Linux package node you configured and add or replace
the file of the same name on this server. If this is the first Linux package node you are configuring then you can skip this step.
1. [Reconfigure GitLab](../restart_gitlab.md#reconfigure-a-linux-package-installation) for the changes to take effect.
Advanced [configuration options](https://docs.gitlab.com/omnibus/settings/database.html)
are supported and can be added if needed.
<div align="right">
<a type="button" class="btn btn-default" href="#set-up-components">
Back to set up components <i class="fa fa-angle-double-up" aria-hidden="true"></i>
</a>
</div>
#### PostgreSQL post-configuration
SSH in to any of the Patroni nodes on the **primary site**:
1. Check the status of the leader and cluster:
```shell
gitlab-ctl patroni members
```
The output should be similar to the following:
```plaintext
| Cluster | Member | Host | Role | State | TL | Lag in MB | Pending restart |
|---------------|-----------------------------------|-----------|--------|---------|-----|-----------|-----------------|
| postgresql-ha | <PostgreSQL primary hostname> | 10.6.0.21 | Leader | running | 175 | | * |
| postgresql-ha | <PostgreSQL secondary 1 hostname> | 10.6.0.22 | | running | 175 | 0 | * |
| postgresql-ha | <PostgreSQL secondary 2 hostname> | 10.6.0.23 | | running | 175 | 0 | * |
```
If the 'State' column for any node doesn't say "running", check the
[PostgreSQL replication and failover troubleshooting section](../../administration/postgresql/replication_and_failover_troubleshooting.md#pgbouncer-error-error-pgbouncer-cannot-connect-to-server)
before proceeding.
<div align="right">
<a type="button" class="btn btn-default" href="#set-up-components">
Back to set up components <i class="fa fa-angle-double-up" aria-hidden="true"></i>
</a>
</div>
### Configure PgBouncer
Now that the PostgreSQL servers are all set up, let's configure PgBouncer
for tracking and handling reads/writes to the primary database.
NOTE:
PgBouncer is single threaded and doesn't significantly benefit from an increase in CPU cores.
Refer to the [scaling documentation](index.md#scaling-an-environment) for more information.
The following IPs will be used as an example:
- `10.6.0.31`: PgBouncer 1
- `10.6.0.32`: PgBouncer 2
- `10.6.0.33`: PgBouncer 3
1. On each PgBouncer node, edit `/etc/gitlab/gitlab.rb`, and replace
`<consul_password_hash>` and `<pgbouncer_password_hash>` with the
password hashes you [set up previously](#postgresql-nodes):
```ruby
# Disable all components except Pgbouncer and Consul agent
roles(['pgbouncer_role'])
# Configure PgBouncer
pgbouncer['admin_users'] = %w(pgbouncer gitlab-consul)
pgbouncer['users'] = {
'gitlab-consul': {
password: '<consul_password_hash>'
},
'pgbouncer': {
password: '<pgbouncer_password_hash>'
}
}
# Configure Consul agent
consul['watchers'] = %w(postgresql)
consul['configuration'] = {
retry_join: %w(10.6.0.11 10.6.0.12 10.6.0.13)
}
# Enable service discovery for Prometheus
consul['monitoring_service_discovery'] = true
# Set the network addresses that the exporters will listen on
node_exporter['listen_address'] = '0.0.0.0:9100'
```
1. Copy the `/etc/gitlab/gitlab-secrets.json` file from the first Linux package node you configured and add or replace
the file of the same name on this server. If this is the first Linux package node you are configuring then you can skip this step.
1. [Reconfigure GitLab](../restart_gitlab.md#reconfigure-a-linux-package-installation) for the changes to take effect.
If an error `execute[generate databases.ini]` occurs, this is due to an existing
[known issue](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/4713).
It will be resolved when you run a second `reconfigure` after the next step.
1. Create a `.pgpass` file so Consul is able to
reload PgBouncer. Enter the PgBouncer password twice when asked:
```shell
gitlab-ctl write-pgpass --host 127.0.0.1 --database pgbouncer --user pgbouncer --hostuser gitlab-consul
```
1. [Reconfigure GitLab](../restart_gitlab.md#reconfigure-a-linux-package-installation) once again
to resolve any potential errors from the previous steps.
1. Ensure each node is talking to the current primary:
```shell
gitlab-ctl pgb-console # You will be prompted for PGBOUNCER_PASSWORD
```
1. Once the console prompt is available, run the following queries:
```shell
show databases ; show clients ;
```
The output should be similar to the following:
```plaintext
name | host | port | database | force_user | pool_size | reserve_pool | pool_mode | max_connections | current_connections
---------------------+-------------+------+---------------------+------------+-----------+--------------+-----------+-----------------+---------------------
gitlabhq_production | MASTER_HOST | 5432 | gitlabhq_production | | 20 | 0 | | 0 | 0
pgbouncer | | 6432 | pgbouncer | pgbouncer | 2 | 0 | statement | 0 | 0
(2 rows)
type | user | database | state | addr | port | local_addr | local_port | connect_time | request_time | ptr | link | remote_pid | tls
------+-----------+---------------------+---------+----------------+-------+------------+------------+---------------------+---------------------+-----------+------+------------+-----
C | pgbouncer | pgbouncer | active | 127.0.0.1 | 56846 | 127.0.0.1 | 6432 | 2017-08-21 18:09:59 | 2017-08-21 18:10:48 | 0x22b3880 | | 0 |
(2 rows)
```
<div align="right">
<a type="button" class="btn btn-default" href="#set-up-components">
Back to set up components <i class="fa fa-angle-double-up" aria-hidden="true"></i>
</a>
</div>
## Configure Redis
Using [Redis](https://redis.io/) in scalable environment is possible using a **Primary** x **Replica**
topology with a [Redis Sentinel](https://redis.io/docs/latest/operate/oss_and_stack/management/sentinel/) service to watch and automatically
start the failover procedure.
NOTE:
Redis clusters must each be deployed in an odd number of 3 nodes or more. This is to ensure Redis Sentinel can take votes as part of a quorum. This does not apply when configuring Redis externally, such as a cloud provider service.
NOTE:
Redis is primarily single threaded and doesn't significantly benefit from an increase in CPU cores. For this size of architecture it's strongly recommended having separate Cache and Persistent instances as specified to achieve optimum performance.
Refer to the [scaling documentation](index.md#scaling-an-environment) for more information.
Redis requires authentication if used with Sentinel. See
[Redis Security](https://redis.io/docs/latest/operate/rc/security/) documentation for more
information. We recommend using a combination of a Redis password and tight
firewall rules to secure your Redis service.
You are highly encouraged to read the [Redis Sentinel](https://redis.io/docs/latest/operate/oss_and_stack/management/sentinel/) documentation
before configuring Redis with GitLab to fully understand the topology and
architecture.
The requirements for a Redis setup are the following:
1. All Redis nodes must be able to talk to each other and accept incoming
connections over Redis (`6379`) and Sentinel (`26379`) ports (unless you
change the default ones).
1. The server that hosts the GitLab application must be able to access the
Redis nodes.
1. Protect the nodes from access from external networks
(Internet),
using a firewall.
In this section, you'll be guided through configuring two external Redis clusters
to be used with GitLab. The following IPs will be used as an example:
- `10.6.0.51`: Redis - Cache Primary
- `10.6.0.52`: Redis - Cache Replica 1
- `10.6.0.53`: Redis - Cache Replica 2
- `10.6.0.61`: Redis - Persistent Primary
- `10.6.0.62`: Redis - Persistent Replica 1
- `10.6.0.63`: Redis - Persistent Replica 2
### Provide your own Redis instances
You can optionally use a [third party external service for the Redis Cache and Persistence instances](../redis/replication_and_failover_external.md#redis-as-a-managed-service-in-a-cloud-provider) with the following guidance:
- A reputable provider or solution should be used for this. [Google Memorystore](https://cloud.google.com/memorystore/docs/redis/memorystore-for-redis-overview) and [AWS ElastiCache](https://docs.aws.amazon.com/AmazonElastiCache/latest/red-ug/WhatIs.html) are known to work.
- Redis Cluster mode is specifically not supported, but Redis Standalone with HA is.
- You must set the [Redis eviction mode](../redis/replication_and_failover_external.md#setting-the-eviction-policy) according to your setup.
For more information, see [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services).
### Configure the Redis Cache cluster
This is the section where we install and set up the new Redis Cache instances.
Both the primary and replica Redis nodes need the same password defined in
`redis['password']`. At any time during a failover, the Sentinels can reconfigure
a node and change its status from primary to replica (and vice versa).
#### Configure the primary Redis Cache node
1. SSH in to the **Primary** Redis server.
1. [Download and install](https://about.gitlab.com/install/) the Linux
package of your choice. Be sure to follow _only_ installation steps 1 and 2
on the page, and to select the correct Linux package, with the same version
and type (Community or Enterprise editions) as your current install.
1. Edit `/etc/gitlab/gitlab.rb` and add the contents:
```ruby
# Specify server role as 'redis_sentinel_role' 'redis_master_role'
roles ['redis_sentinel_role', 'redis_master_role', 'consul_role']
# Set IP bind address and Quorum number for Redis Sentinel service
sentinel['bind'] = '0.0.0.0'
sentinel['quorum'] = 2
# IP address pointing to a local IP that the other machines can reach.
# You can also set bind to '0.0.0.0' which listen in all interfaces.
# If you really need to bind to an external accessible IP, make
# sure you add extra firewall rules to prevent unauthorized access.
redis['bind'] = '10.6.0.51'
# Define a port so Redis can listen for TCP requests which will allow other
# machines to connect to it.
redis['port'] = 6379
# Port of primary Redis server for Sentinel, uncomment to change to non default.
# Defaults to `6379`.
# redis['master_port'] = 6379
# Set up password authentication for Redis (use the same password in all nodes).
redis['master_password'] = 'REDIS_PRIMARY_PASSWORD_OF_FIRST_CLUSTER'
# Must be the same in every Redis node.
redis['master_name'] = 'gitlab-redis-cache'
# The IP of this primary Redis node.
redis['master_ip'] = '10.6.0.51'
# Set the Redis Cache instance as an LRU
# 90% of available RAM in MB
redis['maxmemory'] = '13500mb'
redis['maxmemory_policy'] = "allkeys-lru"
redis['maxmemory_samples'] = 5
## Enable service discovery for Prometheus
consul['monitoring_service_discovery'] = true
## The IPs of the Consul server nodes
## You can also use FQDNs and intermix them with IPs
consul['configuration'] = {
retry_join: %w(10.6.0.11 10.6.0.12 10.6.0.13),
}
# Set the network addresses that the exporters will listen on
node_exporter['listen_address'] = '0.0.0.0:9100'
redis_exporter['listen_address'] = '0.0.0.0:9121'
redis_exporter['flags'] = {
'redis.addr' => 'redis://10.6.0.51:6379',
'redis.password' => 'redis-password-goes-here',
}
# Prevent database migrations from running on upgrade automatically
gitlab_rails['auto_migrate'] = false
```
1. Copy the `/etc/gitlab/gitlab-secrets.json` file from the first Linux package node you configured and add or replace
the file of the same name on this server. If this is the first Linux package node you are configuring then you can skip this step.
1. [Reconfigure GitLab](../restart_gitlab.md#reconfigure-a-linux-package-installation) for the changes to take effect.
#### Configure the replica Redis Cache nodes
1. SSH in to the **replica** Redis server.
1. [Download and install](https://about.gitlab.com/install/) the Linux
package of your choice. Be sure to both follow _only_ installation steps 1 and 2
on the page, and to select the correct Linux package, with the same version
and type (Community or Enterprise editions) as your current install.
1. Edit `/etc/gitlab/gitlab.rb` and add the same contents as the primary node in the previous section replacing `redis_master_node` with `redis_replica_node`:
```ruby
# Specify server role as 'redis_replica_role' and enable Consul agent
roles ['redis_sentinel_role', 'redis_replica_role', 'consul_role']
# Set IP bind address and Quorum number for Redis Sentinel service
sentinel['bind'] = `0.0.0.0`
sentinel['quorum'] = 2
# IP address pointing to a local IP that the other machines can reach.
# Set bind to '0.0.0.0' to listen on all interfaces.
# If you really need to bind to an external accessible IP, make
# sure you add extra firewall rules to prevent unauthorized access.
redis['bind'] = '10.6.0.52'
# Define a port so Redis can listen for TCP requests which will allow other
# machines to connect to it.
redis['port'] = 6379
## Port of primary Redis server for Sentinel, uncomment to change to non default. Defaults
## to `6379`.
#redis['master_port'] = 6379
# Set up password authentication for Redis and replicas (use the same password in all nodes).
redis['master_password'] = 'REDIS_PRIMARY_PASSWORD_OF_FIRST_CLUSTER'
# Must be the same in every Redis node
redis['master_name'] = 'gitlab-redis-cache'
# The IP of the primary Redis node.
redis['master_ip'] = '10.6.0.51'
# Set the Redis Cache instance as an LRU
# 90% of available RAM in MB
redis['maxmemory'] = '13500mb'
redis['maxmemory_policy'] = "allkeys-lru"
redis['maxmemory_samples'] = 5
## Enable service discovery for Prometheus
consul['monitoring_service_discovery'] = true
## The IPs of the Consul server nodes
## You can also use FQDNs and intermix them with IPs
consul['configuration'] = {
retry_join: %w(10.6.0.11 10.6.0.12 10.6.0.13),
}
# Set the network addresses that the exporters will listen on
node_exporter['listen_address'] = '0.0.0.0:9100'
redis_exporter['listen_address'] = '0.0.0.0:9121'
redis_exporter['flags'] = {
'redis.addr' => 'redis://10.6.0.52:6379',
'redis.password' => 'redis-password-goes-here',
}
# Prevent database migrations from running on upgrade automatically
gitlab_rails['auto_migrate'] = false
```
1. Copy the `/etc/gitlab/gitlab-secrets.json` file from the first Linux package node you configured and add or replace
the file of the same name on this server. If this is the first Linux package node you are configuring then you can skip this step.
1. [Reconfigure GitLab](../restart_gitlab.md#reconfigure-a-linux-package-installation) for the changes to take effect.
1. Go through the steps again for all the other replica nodes, and
make sure to set up the IPs correctly.
Advanced [configuration options](https://docs.gitlab.com/omnibus/settings/redis.html) are supported and can be added if needed.
<div align="right">
<a type="button" class="btn btn-default" href="#set-up-components">
Back to set up components <i class="fa fa-angle-double-up" aria-hidden="true"></i>
</a>
</div>
### Configure the Redis Persistent cluster
This is the section where we install and set up the new Redis Persistent instances.
Both the primary and replica Redis nodes need the same password defined in
`redis['password']`. At any time during a failover, the Sentinels can reconfigure
a node and change its status from primary to replica (and vice versa).
#### Configure the primary Redis Persistent node
1. SSH in to the **Primary** Redis server.
1. [Download and install](https://about.gitlab.com/install/) the Linux
package of your choice. Be sure to both follow _only_ installation steps 1 and 2
on the page, and to select the correct Linux package, with the same version
and type (Community or Enterprise editions) as your current install.
1. Edit `/etc/gitlab/gitlab.rb` and add the contents:
```ruby
# Specify server roles as 'redis_sentinel_role' and 'redis_master_role'
roles ['redis_sentinel_role', 'redis_master_role', 'consul_role']
# Set IP bind address and Quorum number for Redis Sentinel service
sentinel['bind'] = '0.0.0.0'
sentinel['quorum'] = 2
# IP address pointing to a local IP that the other machines can reach to.
# You can also set bind to '0.0.0.0' which listen in all interfaces.
# If you really need to bind to an external accessible IP, make
# sure you add extra firewall rules to prevent unauthorized access.
redis['bind'] = '10.6.0.61'
# Define a port so Redis can listen for TCP requests which will allow other
# machines to connect to it.
redis['port'] = 6379
## Port of primary Redis server for Sentinel, uncomment to change to non default. Defaults
## to `6379`.
#redis['master_port'] = 6379
# Set up password authentication for Redis and replicas (use the same password in all nodes).
redis['password'] = 'REDIS_PRIMARY_PASSWORD_OF_SECOND_CLUSTER'
redis['master_password'] = 'REDIS_PRIMARY_PASSWORD_OF_SECOND_CLUSTER'
## Must be the same in every Redis node
redis['master_name'] = 'gitlab-redis-persistent'
## The IP of this primary Redis node.
redis['master_ip'] = '10.6.0.61'
## Enable service discovery for Prometheus
consul['monitoring_service_discovery'] = true
## The IPs of the Consul server nodes
## You can also use FQDNs and intermix them with IPs
consul['configuration'] = {
retry_join: %w(10.6.0.11 10.6.0.12 10.6.0.13),
}
# Set the network addresses that the exporters will listen on
node_exporter['listen_address'] = '0.0.0.0:9100'
redis_exporter['listen_address'] = '0.0.0.0:9121'
# Prevent database migrations from running on upgrade automatically
gitlab_rails['auto_migrate'] = false
```
1. Copy the `/etc/gitlab/gitlab-secrets.json` file from the first Linux package node you configured and add or replace
the file of the same name on this server. If this is the first Linux package node you are configuring then you can skip this step.
1. [Reconfigure GitLab](../restart_gitlab.md#reconfigure-a-linux-package-installation) for the changes to take effect.
#### Configure the replica Redis Persistent nodes
1. SSH in to the **replica** Redis Persistent server.
1. [Download and install](https://about.gitlab.com/install/) the Linux
package of your choice. Be sure to both follow _only_ installation steps 1 and 2
on the page, and to select the correct Linux package, with the same version
and type (Community or Enterprise editions) as your current install.
1. Edit `/etc/gitlab/gitlab.rb` and add the contents:
```ruby
# Specify server role as 'redis_replica_role' and enable Consul agent
roles ['redis_sentinel_role', 'redis_replica_role', 'consul_role']
# Set IP bind address and Quorum number for Redis Sentinel service
sentinel['bind'] = '0.0.0.0'
sentinel['quorum'] = 2
# IP address pointing to a local IP that the other machines can reach to.
# You can also set bind to '0.0.0.0' which listen in all interfaces.
# If you really need to bind to an external accessible IP, make
# sure you add extra firewall rules to prevent unauthorized access.
redis['bind'] = '10.6.0.62'
# Define a port so Redis can listen for TCP requests which will allow other
# machines to connect to it.
redis['port'] = 6379
## Port of primary Redis server for Sentinel, uncomment to change to non default. Defaults
## to `6379`.
#redis['master_port'] = 6379
# The same password for Redis authentication you set up for the primary node.
redis['master_password'] = 'REDIS_PRIMARY_PASSWORD_OF_SECOND_CLUSTER'
## Must be the same in every Redis node
redis['master_name'] = 'gitlab-redis-persistent'
# The IP of the primary Redis node.
redis['master_ip'] = '10.6.0.61'
## Enable service discovery for Prometheus
consul['monitoring_service_discovery'] = true
## The IPs of the Consul server nodes
## You can also use FQDNs and intermix them with IPs
consul['configuration'] = {
retry_join: %w(10.6.0.11 10.6.0.12 10.6.0.13),
}
# Set the network addresses that the exporters will listen on
node_exporter['listen_address'] = '0.0.0.0:9100'
redis_exporter['listen_address'] = '0.0.0.0:9121'
redis_exporter['flags'] = {
'redis.addr' => 'redis://10.6.0.62:6379',
'redis.password' => 'redis-password-goes-here',
}
# Prevent database migrations from running on upgrade automatically
gitlab_rails['auto_migrate'] = false
```
1. Copy the `/etc/gitlab/gitlab-secrets.json` file from the first Linux package node you configured and add or replace
the file of the same name on this server. If this is the first Linux package node you are configuring then you can skip this step.
1. [Reconfigure GitLab](../restart_gitlab.md#reconfigure-a-linux-package-installation) for the changes to take effect.
1. Go through the steps again for all the other replica nodes, and
make sure to set up the IPs correctly.
Advanced [configuration options](https://docs.gitlab.com/omnibus/settings/redis.html)
are supported and can be added if needed.
<div align="right">
<a type="button" class="btn btn-default" href="#set-up-components">
Back to set up components <i class="fa fa-angle-double-up" aria-hidden="true"></i>
</a>
</div>
## Configure Gitaly Cluster
[Gitaly Cluster](../gitaly/praefect.md) is a GitLab-provided and recommended fault tolerant solution for storing Git
repositories. In this configuration, every Git repository is stored on every Gitaly node in the cluster, with one being
designated the primary, and failover occurs automatically if the primary node goes down.
WARNING:
**Gitaly specifications are based on high percentiles of both usage patterns and repository sizes in good health.**
**However, if you have [large monorepos](index.md#large-monorepos) (larger than several gigabytes) or [additional workloads](index.md#additional-workloads) these can *significantly* impact the performance of the environment and further adjustments may be required.**
If this applies to you, we strongly recommended referring to the linked documentation as well as reaching out to your [Customer Success Manager](https://handbook.gitlab.com/job-families/sales/customer-success-management/) or our [Support team](https://about.gitlab.com/support/) for further guidance.
Gitaly Cluster provides the benefits of fault tolerance, but comes with additional complexity of setup and management.
Review the existing [technical limitations and considerations before deploying Gitaly Cluster](../gitaly/index.md#before-deploying-gitaly-cluster).
For guidance on:
- Implementing sharded Gitaly instead, follow the [separate Gitaly documentation](../gitaly/configure_gitaly.md)
instead of this section. Use the same Gitaly specs.
- Migrating existing repositories that aren't managed by Gitaly Cluster, see
[migrate to Gitaly Cluster](../gitaly/index.md#migrate-to-gitaly-cluster).
The recommended cluster setup includes the following components:
- 3 Gitaly nodes: Replicated storage of Git repositories.
- 3 Praefect nodes: Router and transaction manager for Gitaly Cluster.
- 1 Praefect PostgreSQL node: Database server for Praefect. A third-party solution
is required for Praefect database connections to be made highly available.
- 1 load balancer: A load balancer is required for Praefect. The
[internal load balancer](#configure-the-internal-load-balancer) is used.
This section details how to configure the recommended standard setup in order.
For more advanced setups refer to the [standalone Gitaly Cluster documentation](../gitaly/praefect.md).
### Configure Praefect PostgreSQL
Praefect, the routing and transaction manager for Gitaly Cluster, requires its own database server to store data on Gitaly Cluster status.
If you want to have a highly available setup, Praefect requires a third-party PostgreSQL database.
A built-in solution is being [worked on](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/7292).
#### Praefect non-HA PostgreSQL standalone using the Linux package
The following IPs will be used as an example:
- `10.6.0.141`: Praefect PostgreSQL
First, make sure to [install](https://about.gitlab.com/install/)
the Linux GitLab package in the Praefect PostgreSQL node. Following the steps,
install the necessary dependencies from step 1, and add the
GitLab package repository from step 2. When installing GitLab
in the second step, do not supply the `EXTERNAL_URL` value.
1. SSH in to the Praefect PostgreSQL node.
1. Create a strong password to be used for the Praefect PostgreSQL user. Take note of this password as `<praefect_postgresql_password>`.
1. Generate the password hash for the Praefect PostgreSQL username/password pair. This assumes you will use the default
username of `praefect` (recommended). The command will request the password `<praefect_postgresql_password>`
and confirmation. Use the value that is output by this command in the next
step as the value of `<praefect_postgresql_password_hash>`:
```shell
sudo gitlab-ctl pg-password-md5 praefect
```
1. Edit `/etc/gitlab/gitlab.rb` replacing values noted in the `# START user configuration` section:
```ruby
# Disable all components except PostgreSQL and Consul
roles(['postgres_role', 'consul_role'])
# PostgreSQL configuration
postgresql['listen_address'] = '0.0.0.0'
# Prevent database migrations from running on upgrade automatically
gitlab_rails['auto_migrate'] = false
# Configure the Consul agent
## Enable service discovery for Prometheus
consul['monitoring_service_discovery'] = true
# START user configuration
# Please set the real values as explained in Required Information section
#
# Replace PRAEFECT_POSTGRESQL_PASSWORD_HASH with a generated md5 value
postgresql['sql_user_password'] = "<praefect_postgresql_password_hash>"
# Replace XXX.XXX.XXX.XXX/YY with Network Address
postgresql['trust_auth_cidr_addresses'] = %w(10.6.0.0/24 127.0.0.1/32)
# Set the network addresses that the exporters will listen on for monitoring
node_exporter['listen_address'] = '0.0.0.0:9100'
postgres_exporter['listen_address'] = '0.0.0.0:9187'
## The IPs of the Consul server nodes
## You can also use FQDNs and intermix them with IPs
consul['configuration'] = {
retry_join: %w(10.6.0.11 10.6.0.12 10.6.0.13),
}
#
# END user configuration
```
1. Copy the `/etc/gitlab/gitlab-secrets.json` file from the first Linux package node you configured and add or replace
the file of the same name on this server. If this is the first Linux package node you are configuring then you can skip this step.
1. [Reconfigure GitLab](../restart_gitlab.md#reconfigure-a-linux-package-installation) for the changes to take effect.
1. Follow the [post configuration](#praefect-postgresql-post-configuration).
<div align="right">
<a type="button" class="btn btn-default" href="#set-up-components">
Back to set up components <i class="fa fa-angle-double-up" aria-hidden="true"></i>
</a>
</div>
#### Praefect HA PostgreSQL third-party solution
[As noted](#configure-praefect-postgresql), a third-party PostgreSQL solution for
Praefect's database is recommended if aiming for full High Availability.
There are many third-party solutions for PostgreSQL HA. The solution selected must have the following to work with Praefect:
- A static IP for all connections that doesn't change on failover.
- [`LISTEN`](https://www.postgresql.org/docs/12/sql-listen.html) SQL functionality must be supported.
NOTE:
With a third-party setup, it's possible to colocate Praefect's database on the same server as
the main [GitLab](#provide-your-own-postgresql-instance) database as a convenience unless
you are using Geo, where separate database instances are required for handling replication correctly.
In this setup, the specs of the main database setup shouldn't need to be changed as the impact should be
minimal.
A reputable provider or solution should be used for this. [Google Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal)
and [Amazon RDS](https://aws.amazon.com/rds/) are known to work. However, Amazon Aurora is **incompatible** with load balancing enabled by default from
[14.4.0](https://docs.gitlab.com/17.3/ee/update/versions/gitlab_14_changes.html#1440).
See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information.
Once the database is set up, follow the [post configuration](#praefect-postgresql-post-configuration).
#### Praefect PostgreSQL post-configuration
After the Praefect PostgreSQL server has been set up, you'll then need to configure the user and database for Praefect to use.
We recommend the user be named `praefect` and the database `praefect_production`, and these can be configured as standard in PostgreSQL.
The password for the user is the same as the one you configured earlier as `<praefect_postgresql_password>`.
This is how this would work with a Linux package PostgreSQL setup:
1. SSH in to the Praefect PostgreSQL node.
1. Connect to the PostgreSQL server with administrative access.
The `gitlab-psql` user should be used here for this as it's added by default in the Linux package.
The database `template1` is used because it is created by default on all PostgreSQL servers.
```shell
/opt/gitlab/embedded/bin/psql -U gitlab-psql -d template1 -h POSTGRESQL_SERVER_ADDRESS
```
1. Create the new user `praefect`, replacing `<praefect_postgresql_password>`:
```shell
CREATE ROLE praefect WITH LOGIN CREATEDB PASSWORD '<praefect_postgresql_password>';
```
1. Reconnect to the PostgreSQL server, this time as the `praefect` user:
```shell
/opt/gitlab/embedded/bin/psql -U praefect -d template1 -h POSTGRESQL_SERVER_ADDRESS
```
1. Create a new database `praefect_production`:
```shell
CREATE DATABASE praefect_production WITH ENCODING=UTF8;
```
<div align="right">
<a type="button" class="btn btn-default" href="#set-up-components">
Back to set up components <i class="fa fa-angle-double-up" aria-hidden="true"></i>
</a>
</div>
### Configure Praefect
Praefect is the router and transaction manager for Gitaly Cluster and all connections to Gitaly go through
it. This section details how to configure it.
NOTE:
Praefect must be deployed in an odd number of 3 nodes or more. This is to ensure the nodes can take votes as part of a quorum.
Praefect requires several secret tokens to secure communications across the Cluster:
- `<praefect_external_token>`: Used for repositories hosted on your Gitaly cluster and can only be accessed by Gitaly clients that carry this token.
- `<praefect_internal_token>`: Used for replication traffic inside your Gitaly cluster. This is distinct from `praefect_external_token` because Gitaly clients must not be able to access internal nodes of the Praefect cluster directly; that could lead to data loss.
- `<praefect_postgresql_password>`: The Praefect PostgreSQL password defined in the previous section is also required as part of this setup.
Gitaly Cluster nodes are configured in Praefect via a `virtual storage`. Each storage contains
the details of each Gitaly node that makes up the cluster. Each storage is also given a name
and this name is used in several areas of the configuration. In this guide, the name of the storage will be
`default`. Also, this guide is geared towards new installs, if upgrading an existing environment
to use Gitaly Cluster, you may need to use a different name.
Refer to the [Praefect documentation](../gitaly/praefect.md#praefect) for more information.
The following IPs will be used as an example:
- `10.6.0.131`: Praefect 1
- `10.6.0.132`: Praefect 2
- `10.6.0.133`: Praefect 3
To configure the Praefect nodes, on each one:
1. SSH in to the Praefect server.
1. [Download and install](https://about.gitlab.com/install/) the Linux package
of your choice. Be sure to follow _only_ installation steps 1 and 2
on the page.
1. Edit the `/etc/gitlab/gitlab.rb` file to configure Praefect:
NOTE:
You can't remove the `default` entry from `virtual_storages` because [GitLab requires it](../gitaly/configure_gitaly.md#gitlab-requires-a-default-repository-storage).
<!--
Updates to example must be made at:
- https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/administration/gitaly/praefect.md
- all reference architecture pages
-->
```ruby
# Avoid running unnecessary services on the Praefect server
gitaly['enable'] = false
postgresql['enable'] = false
redis['enable'] = false
nginx['enable'] = false
puma['enable'] = false
sidekiq['enable'] = false
gitlab_workhorse['enable'] = false
prometheus['enable'] = false
alertmanager['enable'] = false
gitlab_exporter['enable'] = false
gitlab_kas['enable'] = false
# Praefect Configuration
praefect['enable'] = true
# Prevent database migrations from running on upgrade automatically
praefect['auto_migrate'] = false
gitlab_rails['auto_migrate'] = false
# Configure the Consul agent
consul['enable'] = true
## Enable service discovery for Prometheus
consul['monitoring_service_discovery'] = true
# START user configuration
# Please set the real values as explained in Required Information section
#
praefect['configuration'] = {
# ...
listen_addr: '0.0.0.0:2305',
auth: {
# ...
#
# Praefect External Token
# This is needed by clients outside the cluster (like GitLab Shell) to communicate with the Praefect cluster
token: '<praefect_external_token>',
},
# Praefect Database Settings
database: {
# ...
host: '10.6.0.141',
port: 5432,
dbname: 'praefect_production',
user: 'praefect',
password: '<praefect_postgresql_password>',
},
# Praefect Virtual Storage config
# Name of storage hash must match storage name in git_data_dirs on GitLab
# server ('praefect') and in gitaly['configuration'][:storage] on Gitaly nodes ('gitaly-1')
virtual_storage: [
{
# ...
name: 'default',
node: [
{
storage: 'gitaly-1',
address: 'tcp://10.6.0.91:8075',
token: '<praefect_internal_token>'
},
{
storage: 'gitaly-2',
address: 'tcp://10.6.0.92:8075',
token: '<praefect_internal_token>'
},
{
storage: 'gitaly-3',
address: 'tcp://10.6.0.93:8075',
token: '<praefect_internal_token>'
},
],
},
],
# Set the network address Praefect will listen on for monitoring
prometheus_listen_addr: '0.0.0.0:9652',
}
# Set the network address the node exporter will listen on for monitoring
node_exporter['listen_address'] = '0.0.0.0:9100'
## The IPs of the Consul server nodes
## You can also use FQDNs and intermix them with IPs
consul['configuration'] = {
retry_join: %w(10.6.0.11 10.6.0.12 10.6.0.13),
}
#
# END user configuration
```
1. Copy the `/etc/gitlab/gitlab-secrets.json` file from the first Linux package node you configured and add or replace
the file of the same name on this server. If this is the first Linux package node you are configuring then you can skip this step.
1. Praefect requires to run some database migrations, much like the main GitLab application. For this
you should select **one Praefect node only to run the migrations**, AKA the _Deploy Node_. This node
must be configured first before the others as follows:
1. In the `/etc/gitlab/gitlab.rb` file, change the `praefect['auto_migrate']` setting value from `false` to `true`
1. To ensure database migrations are only run during reconfigure and not automatically on upgrade, run:
```shell
sudo touch /etc/gitlab/skip-auto-reconfigure
```
1. [Reconfigure GitLab](../restart_gitlab.md#reconfigure-a-linux-package-installation) for the changes to take effect and
to run the Praefect database migrations.
1. On all other Praefect nodes, [reconfigure GitLab](../restart_gitlab.md#reconfigure-a-linux-package-installation) for the changes to take effect.
### Configure Gitaly
The [Gitaly](../gitaly/index.md) server nodes that make up the cluster have
requirements that are dependent on data and load.
WARNING:
**Gitaly specifications are based on high percentiles of both usage patterns and repository sizes in good health.**
**However, if you have [large monorepos](index.md#large-monorepos) (larger than several gigabytes) or [additional workloads](index.md#additional-workloads) these can *significantly* impact the performance of the environment and further adjustments may be required.**
If this applies to you, we strongly recommended referring to the linked documentation as well as reaching out to your [Customer Success Manager](https://handbook.gitlab.com/job-families/sales/customer-success-management/) or our [Support team](https://about.gitlab.com/support/) for further guidance.
Due to Gitaly having notable input and output requirements, we strongly
recommend that all Gitaly nodes use solid-state drives (SSDs). These SSDs
should have a throughput of at least 8,000
input/output operations per second (IOPS) for read operations and 2,000 IOPS for
write operations. If you're running the environment on a Cloud provider,
refer to their documentation about how to configure IOPS correctly.
Gitaly servers must not be exposed to the public internet, as network traffic
on Gitaly is unencrypted by default. The use of a firewall is highly recommended
to restrict access to the Gitaly server. Another option is to
[use TLS](#gitaly-cluster-tls-support).
For configuring Gitaly you should note the following:
- `gitaly['configuration'][:storage]` should be configured to reflect the storage path for the specific Gitaly node
- `auth_token` should be the same as `praefect_internal_token`
The following IPs will be used as an example:
- `10.6.0.91`: Gitaly 1
- `10.6.0.92`: Gitaly 2
- `10.6.0.93`: Gitaly 3
On each node:
1. [Download and install](https://about.gitlab.com/install/) the Linux package
of your choice. Be sure to follow _only_ installation steps 1 and 2
on the page, and _do not_ provide the `EXTERNAL_URL` value.
1. Edit the Gitaly server node's `/etc/gitlab/gitlab.rb` file to configure
storage paths, enable the network listener, and to configure the token:
<!--
Updates to example must be made at:
- https://gitlab.com/gitlab-org/charts/gitlab/blob/master/doc/advanced/external-gitaly/external-omnibus-gitaly.md#configure-omnibus-gitlab
- https://gitlab.com/gitlab-org/gitlab/blob/master/doc/administration/gitaly/index.md#gitaly-server-configuration
- all reference architecture pages
-->
```ruby
# Avoid running unnecessary services on the Gitaly server
postgresql['enable'] = false
redis['enable'] = false
nginx['enable'] = false
puma['enable'] = false
sidekiq['enable'] = false
gitlab_workhorse['enable'] = false
prometheus['enable'] = false
alertmanager['enable'] = false
gitlab_exporter['enable'] = false
gitlab_kas['enable'] = false
# Prevent database migrations from running on upgrade automatically
gitlab_rails['auto_migrate'] = false
# Configure the gitlab-shell API callback URL. Without this, `git push` will
# fail. This can be your 'front door' GitLab URL or an internal load
# balancer.
gitlab_rails['internal_api_url'] = 'https://gitlab.example.com'
# Gitaly
gitaly['enable'] = true
# Configure the Consul agent
consul['enable'] = true
## Enable service discovery for Prometheus
consul['monitoring_service_discovery'] = true
# START user configuration
# Please set the real values as explained in Required Information section
#
## The IPs of the Consul server nodes
## You can also use FQDNs and intermix them with IPs
consul['configuration'] = {
retry_join: %w(10.6.0.11 10.6.0.12 10.6.0.13),
}
# Set the network address that the node exporter will listen on for monitoring
node_exporter['listen_address'] = '0.0.0.0:9100'
gitaly['configuration'] = {
# Make Gitaly accept connections on all network interfaces. You must use
# firewalls to restrict access to this address/port.
# Comment out following line if you only want to support TLS connections
listen_addr: '0.0.0.0:8075',
# Set the network address that Gitaly will listen on for monitoring
prometheus_listen_addr: '0.0.0.0:9236',
auth: {
# Gitaly Auth Token
# Should be the same as praefect_internal_token
token: '<praefect_internal_token>',
},
pack_objects_cache: {
# Gitaly Pack-objects cache
# Recommended to be enabled for improved performance but can notably increase disk I/O
# Refer to https://docs.gitlab.com/ee/administration/gitaly/configure_gitaly.html#pack-objects-cache for more info
enabled: true,
},
}
#
# END user configuration
```
1. Append the following to `/etc/gitlab/gitlab.rb` for each respective server:
- On Gitaly node 1:
```ruby
gitaly['configuration'] = {
# ...
storage: [
{
name: 'gitaly-1',
path: '/var/opt/gitlab/git-data',
},
],
}
```
- On Gitaly node 2:
```ruby
gitaly['configuration'] = {
# ...
storage: [
{
name: 'gitaly-2',
path: '/var/opt/gitlab/git-data',
},
],
}
```
- On Gitaly node 3:
```ruby
gitaly['configuration'] = {
# ...
storage: [
{
name: 'gitaly-3',
path: '/var/opt/gitlab/git-data',
},
],
}
```
1. Copy the `/etc/gitlab/gitlab-secrets.json` file from the first Linux package node you configured and add or replace
the file of the same name on this server. If this is the first Linux package node you are configuring then you can skip this step.
1. Save the file, and then [reconfigure GitLab](../restart_gitlab.md#reconfigure-a-linux-package-installation).
### Gitaly Cluster TLS support
Praefect supports TLS encryption. To communicate with a Praefect instance that listens
for secure connections, you must:
- Use a `tls://` URL scheme in the `gitaly_address` of the corresponding storage entry
in the GitLab configuration.
- Bring your own certificates because this isn't provided automatically. The certificate
corresponding to each Praefect server must be installed on that Praefect server.
Additionally the certificate, or its certificate authority, must be installed on all Gitaly servers
and on all Praefect clients that communicate with it following the procedure described in
[GitLab custom certificate configuration](https://docs.gitlab.com/omnibus/settings/ssl/index.html#install-custom-public-certificates) (and repeated below).
Note the following:
- The certificate must specify the address you use to access the Praefect server. You must add the hostname or IP
address as a Subject Alternative Name to the certificate.
- You can configure Praefect servers with both an unencrypted listening address
`listen_addr` and an encrypted listening address `tls_listen_addr` at the same time.
This allows you to do a gradual transition from unencrypted to encrypted traffic, if
necessary. To disable the unencrypted listener, set `praefect['configuration'][:listen_addr] = nil`.
- The Internal Load Balancer will also access to the certificates and need to be configured
to allow for TLS passthrough.
Refer to the load balancers documentation on how to configure this.
To configure Praefect with TLS:
1. Create certificates for Praefect servers.
1. On the Praefect servers, create the `/etc/gitlab/ssl` directory and copy your key
and certificate there:
```shell
sudo mkdir -p /etc/gitlab/ssl
sudo chmod 755 /etc/gitlab/ssl
sudo cp key.pem cert.pem /etc/gitlab/ssl/
sudo chmod 644 key.pem cert.pem
```
1. Edit `/etc/gitlab/gitlab.rb` and add:
```ruby
praefect['configuration'] = {
# ...
tls_listen_addr: '0.0.0.0:3305',
tls: {
# ...
certificate_path: '/etc/gitlab/ssl/cert.pem',
key_path: '/etc/gitlab/ssl/key.pem',
},
}
```
1. Save the file and [reconfigure](../restart_gitlab.md#reconfigure-a-linux-package-installation).
1. On the Praefect clients (including each Gitaly server), copy the certificates,
or their certificate authority, into `/etc/gitlab/trusted-certs`:
```shell
sudo cp cert.pem /etc/gitlab/trusted-certs/
```
1. On the Praefect clients (except Gitaly servers), edit `git_data_dirs` in
`/etc/gitlab/gitlab.rb` as follows:
```ruby
git_data_dirs({
"default" => {
"gitaly_address" => 'tls://LOAD_BALANCER_SERVER_ADDRESS:3305',
"gitaly_token" => 'PRAEFECT_EXTERNAL_TOKEN'
}
})
```
1. Save the file and [reconfigure GitLab](../restart_gitlab.md#reconfigure-a-linux-package-installation).
<div align="right">
<a type="button" class="btn btn-default" href="#set-up-components">
Back to set up components <i class="fa fa-angle-double-up" aria-hidden="true"></i>
</a>
</div>
## Configure Sidekiq
Sidekiq requires connection to the [Redis](#configure-redis),
[PostgreSQL](#configure-postgresql) and [Gitaly](#configure-gitaly) instances.
It also requires a connection to [Object Storage](#configure-the-object-storage) as recommended.
NOTE:
[Because it's recommended to use Object storage](../object_storage.md) instead of NFS for data objects, the following
examples include the Object storage configuration.
NOTE:
If you find that the environment's Sidekiq job processing is slow with long queues
you can scale it accordingly. Refer to the [scaling documentation](index.md#scaling-an-environment) for more information.
NOTE:
When configuring additional GitLab functionality such as Container Registry, SAML, or LDAP,
update the Sidekiq configuration in addition to the Rails configuration.
Refer to the [external Sidekiq documentation](../sidekiq/index.md) for more information.
- `10.6.0.101`: Sidekiq 1
- `10.6.0.102`: Sidekiq 2
- `10.6.0.103`: Sidekiq 3
- `10.6.0.104`: Sidekiq 4
To configure the Sidekiq nodes, on each one:
1. SSH in to the Sidekiq server.
1. Confirm that you can access the PostgreSQL, Gitaly, and Redis ports:
```shell
telnet <GitLab host> 5432 # PostgreSQL
telnet <GitLab host> 8075 # Gitaly
telnet <GitLab host> 6379 # Redis
```
1. [Download and install](https://about.gitlab.com/install/) the Linux
package of your choice. Be sure to follow _only_ installation steps 1 and 2
on the page.
1. Create or edit `/etc/gitlab/gitlab.rb` and use the following configuration:
```ruby
# https://docs.gitlab.com/omnibus/roles/#sidekiq-roles
roles(["sidekiq_role"])
# External URL
## This should match the URL of the external load balancer
external_url 'https://gitlab.example.com'
# Redis
## Redis connection details
## First cluster that will host the cache data
gitlab_rails['redis_cache_instance'] = 'redis://:<REDIS_PRIMARY_PASSWORD_OF_FIRST_CLUSTER>@gitlab-redis-cache'
gitlab_rails['redis_cache_sentinels'] = [
{host: '10.6.0.51', port: 26379},
{host: '10.6.0.52', port: 26379},
{host: '10.6.0.53', port: 26379},
]
## Second cluster that hosts all other persistent data
redis['master_name'] = 'gitlab-redis-persistent'
redis['master_password'] = '<REDIS_PRIMARY_PASSWORD_OF_SECOND_CLUSTER>'
gitlab_rails['redis_sentinels'] = [
{host: '10.6.0.61', port: 26379},
{host: '10.6.0.62', port: 26379},
{host: '10.6.0.63', port: 26379},
]
# Gitaly Cluster
## git_data_dirs get configured for the Praefect virtual storage
## Address is Internal Load Balancer for Praefect
## Token is praefect_external_token
git_data_dirs({
"default" => {
"gitaly_address" => "tcp://10.6.0.40:2305", # internal load balancer IP
"gitaly_token" => '<praefect_external_token>'
}
})
# PostgreSQL
gitlab_rails['db_host'] = '10.6.0.20' # internal load balancer IP
gitlab_rails['db_port'] = 6432
gitlab_rails['db_password'] = '<postgresql_user_password>'
gitlab_rails['db_load_balancing'] = { 'hosts' => ['10.6.0.21', '10.6.0.22', '10.6.0.23'] } # PostgreSQL IPs
## Prevent database migrations from running on upgrade automatically
gitlab_rails['auto_migrate'] = false
# Sidekiq
sidekiq['listen_address'] = "0.0.0.0"
## Set number of Sidekiq queue processes to the same number as available CPUs
sidekiq['queue_groups'] = ['*'] * 4
# Monitoring
consul['enable'] = true
consul['monitoring_service_discovery'] = true
consul['configuration'] = {
retry_join: %w(10.6.0.11 10.6.0.12 10.6.0.13)
}
## Set the network addresses that the exporters will listen on
node_exporter['listen_address'] = '0.0.0.0:9100'
## Add the monitoring node's IP address to the monitoring whitelist
gitlab_rails['monitoring_whitelist'] = ['10.6.0.151/32', '127.0.0.0/8']
# Object Storage
# This is an example for configuring Object Storage on GCP
# Replace this config with your chosen Object Storage provider as desired
gitlab_rails['object_store']['enabled'] = true
gitlab_rails['object_store']['connection'] = {
'provider' => 'Google',
'google_project' => '<gcp-project-name>',
'google_json_key_location' => '<path-to-gcp-service-account-key>'
}
gitlab_rails['object_store']['objects']['artifacts']['bucket'] = "<gcp-artifacts-bucket-name>"
gitlab_rails['object_store']['objects']['external_diffs']['bucket'] = "<gcp-external-diffs-bucket-name>"
gitlab_rails['object_store']['objects']['lfs']['bucket'] = "<gcp-lfs-bucket-name>"
gitlab_rails['object_store']['objects']['uploads']['bucket'] = "<gcp-uploads-bucket-name>"
gitlab_rails['object_store']['objects']['packages']['bucket'] = "<gcp-packages-bucket-name>"
gitlab_rails['object_store']['objects']['dependency_proxy']['bucket'] = "<gcp-dependency-proxy-bucket-name>"
gitlab_rails['object_store']['objects']['terraform_state']['bucket'] = "<gcp-terraform-state-bucket-name>"
gitlab_rails['backup_upload_connection'] = {
'provider' => 'Google',
'google_project' => '<gcp-project-name>',
'google_json_key_location' => '<path-to-gcp-service-account-key>'
}
gitlab_rails['backup_upload_remote_directory'] = "<gcp-backups-state-bucket-name>"
gitlab_rails['ci_secure_files_object_store_enabled'] = true
gitlab_rails['ci_secure_files_object_store_remote_directory'] = "gcp-ci_secure_files-bucket-name"
gitlab_rails['ci_secure_files_object_store_connection'] = {
'provider' => 'Google',
'google_project' => '<gcp-project-name>',
'google_json_key_location' => '<path-to-gcp-service-account-key>'
}
```
1. Copy the `/etc/gitlab/gitlab-secrets.json` file from the first Linux package node you configured and add or replace
the file of the same name on this server. If this is the first Linux package node you are configuring then you can skip this step.
1. To ensure database migrations are only run during reconfigure and not automatically on upgrade, run:
```shell
sudo touch /etc/gitlab/skip-auto-reconfigure
```
Only a single designated node should handle migrations as detailed in the
[GitLab Rails post-configuration](#gitlab-rails-post-configuration) section.
1. [Reconfigure GitLab](../restart_gitlab.md#reconfigure-a-linux-package-installation) for the changes to take effect.
<div align="right">
<a type="button" class="btn btn-default" href="#set-up-components">
Back to set up components <i class="fa fa-angle-double-up" aria-hidden="true"></i>
</a>
</div>
## Configure GitLab Rails
This section describes how to configure the GitLab application (Rails) component.
Rails requires connections to the [Redis](#configure-redis),
[PostgreSQL](#configure-postgresql) and [Gitaly](#configure-gitaly) instances.
It also requires a connection to [Object Storage](#configure-the-object-storage) as recommended.
NOTE:
[Because it's recommended to use Object storage](../object_storage.md) instead of NFS for data objects, the following
examples include the Object storage configuration.
The following IPs will be used as an example:
- `10.6.0.111`: GitLab application 1
- `10.6.0.112`: GitLab application 2
- `10.6.0.113`: GitLab application 3
- `10.6.0.114`: GitLab application 4
- `10.6.0.115`: GitLab application 5
On each node perform the following:
1. [Download and install](https://about.gitlab.com/install/) the Linux
package of your choice. Be sure to follow _only_ installation steps 1 and 2
on the page.
1. Edit `/etc/gitlab/gitlab.rb` and use the following configuration.
To maintain uniformity of links across nodes, the `external_url`
on the application server should point to the external URL that users will use
to access GitLab. This would be the URL of the [external load balancer](#configure-the-external-load-balancer)
which will route traffic to the GitLab application server:
```ruby
external_url 'https://gitlab.example.com'
# git_data_dirs get configured for the Praefect virtual storage
# Address is Internal Load Balancer for Praefect
# Token is praefect_external_token
git_data_dirs({
"default" => {
"gitaly_address" => "tcp://10.6.0.40:2305", # internal load balancer IP
"gitaly_token" => '<praefect_external_token>'
}
})
## Disable components that will not be on the GitLab application server
roles(['application_role'])
gitaly['enable'] = false
sidekiq['enable'] = false
## PostgreSQL connection details
# Disable PostgreSQL on the application node
postgresql['enable'] = false
gitlab_rails['db_host'] = '10.6.0.20' # internal load balancer IP
gitlab_rails['db_port'] = 6432
gitlab_rails['db_password'] = '<postgresql_user_password>'
gitlab_rails['db_load_balancing'] = { 'hosts' => ['10.6.0.21', '10.6.0.22', '10.6.0.23'] } # PostgreSQL IPs
# Prevent database migrations from running on upgrade automatically
gitlab_rails['auto_migrate'] = false
## Redis connection details
## First cluster that will host the cache data
gitlab_rails['redis_cache_instance'] = 'redis://:<REDIS_PRIMARY_PASSWORD_OF_FIRST_CLUSTER>@gitlab-redis-cache'
gitlab_rails['redis_cache_sentinels'] = [
{host: '10.6.0.51', port: 26379},
{host: '10.6.0.52', port: 26379},
{host: '10.6.0.53', port: 26379},
]
## Second cluster that hosts all other persistent data
redis['master_name'] = 'gitlab-redis-persistent'
redis['master_password'] = '<REDIS_PRIMARY_PASSWORD_OF_SECOND_CLUSTER>'
gitlab_rails['redis_sentinels'] = [
{host: '10.6.0.61', port: 26379},
{host: '10.6.0.62', port: 26379},
{host: '10.6.0.63', port: 26379},
]
# Set the network addresses that the exporters used for monitoring will listen on
node_exporter['listen_address'] = '0.0.0.0:9100'
gitlab_workhorse['prometheus_listen_addr'] = '0.0.0.0:9229'
puma['listen'] = '0.0.0.0'
# Add the monitoring node's IP address to the monitoring whitelist and allow it to
# scrape the NGINX metrics
gitlab_rails['monitoring_whitelist'] = ['10.6.0.151/32', '127.0.0.0/8']
nginx['status']['options']['allow'] = ['10.6.0.151/32', '127.0.0.0/8']
#############################
### Object storage ###
#############################
# This is an example for configuring Object Storage on GCP
# Replace this config with your chosen Object Storage provider as desired
gitlab_rails['object_store']['enabled'] = true
gitlab_rails['object_store']['connection'] = {
'provider' => 'Google',
'google_project' => '<gcp-project-name>',
'google_json_key_location' => '<path-to-gcp-service-account-key>'
}
gitlab_rails['object_store']['objects']['artifacts']['bucket'] = "<gcp-artifacts-bucket-name>"
gitlab_rails['object_store']['objects']['external_diffs']['bucket'] = "<gcp-external-diffs-bucket-name>"
gitlab_rails['object_store']['objects']['lfs']['bucket'] = "<gcp-lfs-bucket-name>"
gitlab_rails['object_store']['objects']['uploads']['bucket'] = "<gcp-uploads-bucket-name>"
gitlab_rails['object_store']['objects']['packages']['bucket'] = "<gcp-packages-bucket-name>"
gitlab_rails['object_store']['objects']['dependency_proxy']['bucket'] = "<gcp-dependency-proxy-bucket-name>"
gitlab_rails['object_store']['objects']['terraform_state']['bucket'] = "<gcp-terraform-state-bucket-name>"
gitlab_rails['backup_upload_connection'] = {
'provider' => 'Google',
'google_project' => '<gcp-project-name>',
'google_json_key_location' => '<path-to-gcp-service-account-key>'
}
gitlab_rails['backup_upload_remote_directory'] = "<gcp-backups-state-bucket-name>"
gitlab_rails['ci_secure_files_object_store_enabled'] = true
gitlab_rails['ci_secure_files_object_store_remote_directory'] = "gcp-ci_secure_files-bucket-name"
gitlab_rails['ci_secure_files_object_store_connection'] = {
'provider' => 'Google',
'google_project' => '<gcp-project-name>',
'google_json_key_location' => '<path-to-gcp-service-account-key>'
}
```
1. If you're using [Gitaly with TLS support](#gitaly-cluster-tls-support), make sure the
`git_data_dirs` entry is configured with `tls` instead of `tcp`:
```ruby
git_data_dirs({
"default" => {
"gitaly_address" => "tls://10.6.0.40:2305", # internal load balancer IP
"gitaly_token" => '<praefect_external_token>'
}
})
```
1. Copy the cert into `/etc/gitlab/trusted-certs`:
```shell
sudo cp cert.pem /etc/gitlab/trusted-certs/
```
1. Copy the `/etc/gitlab/gitlab-secrets.json` file from the first Linux package node you configured and add or replace
the file of the same name on this server. If this is the first Linux package node you are configuring then you can skip this step.
1. Copy the SSH host keys (all in the name format `/etc/ssh/ssh_host_*_key*`) from the first Linux package node you configured and
add or replace the files of the same name on this server. This ensures host mismatch errors aren't thrown
for your users as they hit the load balanced Rails nodes. If this is the first Linux package node you are configuring,
then you can skip this step.
1. To ensure database migrations are only run during reconfigure and not automatically on upgrade, run:
```shell
sudo touch /etc/gitlab/skip-auto-reconfigure
```
Only a single designated node should handle migrations as detailed in the
[GitLab Rails post-configuration](#gitlab-rails-post-configuration) section.
1. [Reconfigure GitLab](../restart_gitlab.md#reconfigure-a-linux-package-installation) for the changes to take effect.
1. [Enable incremental logging](#enable-incremental-logging).
1. Confirm the node can connect to Gitaly:
```shell
sudo gitlab-rake gitlab:gitaly:check
```
Then, tail the logs to see the requests:
```shell
sudo gitlab-ctl tail gitaly
```
1. Optionally, from the Gitaly servers, confirm that Gitaly can perform callbacks to the internal API:
- For GitLab 15.3 and later, run `sudo -u git -- /opt/gitlab/embedded/bin/gitaly check /var/opt/gitlab/gitaly/config.toml`.
- For GitLab 15.2 and earlier, run `sudo -u git -- /opt/gitlab/embedded/bin/gitaly-hooks check /var/opt/gitlab/gitaly/config.toml`.
When you specify `https` in the `external_url`, as in the previous example,
GitLab expects that the SSL certificates are in `/etc/gitlab/ssl/`. If the
certificates aren't present, NGINX will fail to start. For more information, see
the [HTTPS documentation](https://docs.gitlab.com/omnibus/settings/ssl/index.html).
### GitLab Rails post-configuration
1. Designate one application node for running database migrations during
installation and updates. Initialize the GitLab database and ensure all
migrations ran:
```shell
sudo gitlab-rake gitlab:db:configure
```
This operation requires configuring the Rails node to connect to the primary database
directly, [bypassing PgBouncer](../postgresql/pgbouncer.md#procedure-for-bypassing-pgbouncer).
After migrations have completed, you must configure the node to pass through PgBouncer again.
1. [Configure fast lookup of authorized SSH keys in the database](../operations/fast_ssh_key_lookup.md).
<div align="right">
<a type="button" class="btn btn-default" href="#set-up-components">
Back to set up components <i class="fa fa-angle-double-up" aria-hidden="true"></i>
</a>
</div>
## Configure Prometheus
The Linux package can be used to configure a standalone Monitoring node
running [Prometheus](../monitoring/prometheus/index.md).
The following IP will be used as an example:
- `10.6.0.151`: Prometheus
To configure the Monitoring node:
1. SSH in to the Monitoring node.
1. [Download and install](https://about.gitlab.com/install/) the Linux
package of your choice. Be sure to follow _only_ installation steps 1 and 2
on the page.
1. Edit `/etc/gitlab/gitlab.rb` and add the contents:
```ruby
roles(['monitoring_role', 'consul_role'])
external_url 'http://gitlab.example.com'
# Prometheus
prometheus['listen_address'] = '0.0.0.0:9090'
prometheus['monitor_kubernetes'] = false
# Enable service discovery for Prometheus
consul['monitoring_service_discovery'] = true
consul['configuration'] = {
retry_join: %w(10.6.0.11 10.6.0.12 10.6.0.13)
}
# Configure Prometheus to scrape services not covered by discovery
prometheus['scrape_configs'] = [
{
'job_name': 'pgbouncer',
'static_configs' => [
'targets' => [
"10.6.0.31:9188",
"10.6.0.32:9188",
"10.6.0.33:9188",
],
],
},
{
'job_name': 'praefect',
'static_configs' => [
'targets' => [
"10.6.0.131:9652",
"10.6.0.132:9652",
"10.6.0.133:9652",
],
],
},
]
nginx['enable'] = false
```
1. Save the file and [reconfigure GitLab](../restart_gitlab.md#reconfigure-a-linux-package-installation).
<div align="right">
<a type="button" class="btn btn-default" href="#set-up-components">
Back to set up components <i class="fa fa-angle-double-up" aria-hidden="true"></i>
</a>
</div>
## Configure the object storage
GitLab supports using an [object storage](../object_storage.md) service for holding numerous types of data.
It's recommended over [NFS](../nfs.md) for data objects and in general it's better
in larger setups as object storage is typically much more performant, reliable,
and scalable. See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information.
There are two ways of specifying object storage configuration in GitLab:
- [Consolidated form](../object_storage.md#configure-a-single-storage-connection-for-all-object-types-consolidated-form): A single credential is
shared by all supported object types.
- [Storage-specific form](../object_storage.md#configure-each-object-type-to-define-its-own-storage-connection-storage-specific-form): Every object defines its
own object storage [connection and configuration](../object_storage.md#configure-the-connection-settings).
The consolidated form is used in the following examples when available.
Using separate buckets for each data type is the recommended approach for GitLab.
This ensures there are no collisions across the various types of data GitLab stores.
There are plans to [enable the use of a single bucket](https://gitlab.com/gitlab-org/gitlab/-/issues/292958)
in the future.
<div align="right">
<a type="button" class="btn btn-default" href="#set-up-components">
Back to set up components <i class="fa fa-angle-double-up" aria-hidden="true"></i>
</a>
</div>
### Enable incremental logging
GitLab Runner returns job logs in chunks which the Linux package caches temporarily on disk in `/var/opt/gitlab/gitlab-ci/builds` by default, even when using consolidated object storage. With default configuration, this directory needs to be shared through NFS on any GitLab Rails and Sidekiq nodes.
While sharing the job logs through NFS is supported, it's recommended to avoid the need to use NFS by enabling [incremental logging](../cicd/job_logs.md#incremental-logging-architecture) (required when no NFS node has been deployed). Incremental logging uses Redis instead of disk space for temporary caching of job logs.
## Configure advanced search
You can leverage Elasticsearch and [enable advanced search](../../integration/advanced_search/elasticsearch.md)
for faster, more advanced code search across your entire GitLab instance.
Elasticsearch cluster design and requirements are dependent on your specific
data. For recommended best practices about how to set up your Elasticsearch
cluster alongside your instance, read how to
[choose the optimal cluster configuration](../../integration/advanced_search/elasticsearch.md#guidance-on-choosing-optimal-cluster-configuration).
<div align="right">
<a type="button" class="btn btn-default" href="#set-up-components">
Back to set up components <i class="fa fa-angle-double-up" aria-hidden="true"></i>
</a>
</div>
## Cloud Native Hybrid reference architecture with Helm Charts (alternative)
An alternative approach is to run specific GitLab components in Kubernetes.
The following services are supported:
- GitLab Rails
- Sidekiq
- NGINX
- Toolbox
- Migrations
- Prometheus
Hybrid installations leverage the benefits of both cloud native and traditional
compute deployments. With this, _stateless_ components can benefit from cloud native
workload management benefits while _stateful_ components are deployed in compute VMs
with Linux package installations to benefit from increased permanence.
Refer to the Helm charts [Advanced configuration](https://docs.gitlab.com/charts/advanced/)
documentation for setup instructions including guidance on what GitLab secrets to sync
between Kubernetes and the backend components.
NOTE:
This is an **advanced** setup. Running services in Kubernetes is well known
to be complex. **This setup is only recommended** if you have strong working
knowledge and experience in Kubernetes. The rest of this
section assumes this.
WARNING:
**Gitaly Cluster is not supported to be run in Kubernetes**.
Refer to [epic 6127](https://gitlab.com/groups/gitlab-org/-/epics/6127) for more details.
### Cluster topology
The following tables and diagram detail the hybrid environment using the same formats
as the typical environment above.
First are the components that run in Kubernetes. These run across several node groups, although you can change
the overall makeup as desired as long as the minimum CPU and Memory requirements are observed.
| Component Node Group | Target Node Pool Totals | GCP Example | AWS Example |
|----------------------|-------------------------|-----------------|--------------|
| Webservice | 140 vCPU<br/>175 GB memory (request)<br/>245 GB memory (limit) | 5 x `n1-standard-32` | 5 x `c5.9xlarge` |
| Sidekiq | 12.6 vCPU<br/>28 GB memory (request)<br/>56 GB memory (limit) | 4 x `n1-standard-4` | 4 x `m5.xlarge` |
| Supporting services | 8 vCPU<br/>30 GB memory | 2 x `n1-standard-4` | 2 x `m5.xlarge` |
- For this setup, we **recommend** and regularly [test](index.md#validation-and-test-results)
[Google Kubernetes Engine (GKE)](https://cloud.google.com/kubernetes-engine) and [Amazon Elastic Kubernetes Service (EKS)](https://aws.amazon.com/eks/). Other Kubernetes services may also work, but your mileage may vary.
- GCP and AWS examples of how to reach the Target Node Pool Total are given for convenience. These sizes are used in performance testing but following the example is not required. Different node pool designs can be used as desired as long as the targets are met, and all pods can deploy.
- The [Webservice](#webservice) and [Sidekiq](#sidekiq) target node pool totals are given for GitLab components only. Additional resources are required for the chosen Kubernetes provider's system processes. The given examples take this into account.
- The [Supporting](#supporting) target node pool total is given generally to accommodate several resources for supporting the GitLab deployment as well as any additional deployments you may wish to make depending on your requirements. Similar to the other node pools, the chosen Kubernetes provider's system processes also require resources. The given examples take this into account.
- In production deployments, it's not required to assign pods to specific nodes. However, it is recommended to have several nodes in each pool spread across different availability zones to align with resilient cloud architecture practices.
- Enabling autoscaling, such as Cluster Autoscaler, for efficiency reasons is encouraged, but it's generally recommended targeting a floor of 75% for Webservice and Sidekiq pods to ensure ongoing performance.
Next are the backend components that run on static compute VMs using the Linux package (or External PaaS
services where applicable):
| Service | Nodes | Configuration | GCP | AWS |
|------------------------------------------|-------|------------------------|------------------|--------------|
| Consul<sup>1</sup> | 3 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` |
| PostgreSQL<sup>1</sup> | 3 | 16 vCPU, 60 GB memory | `n1-standard-16` | `m5.4xlarge` |
| PgBouncer<sup>1</sup> | 3 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` |
| Internal load balancer<sup>3</sup> | 1 | 8 vCPU, 7.2 GB memory | `n1-highcpu-8` | `c5.2xlarge` |
| Redis/Sentinel - Cache<sup>2</sup> | 3 | 4 vCPU, 15 GB memory | `n1-standard-4` | `m5.xlarge` |
| Redis/Sentinel - Persistent<sup>2</sup> | 3 | 4 vCPU, 15 GB memory | `n1-standard-4` | `m5.xlarge` |
| Gitaly<sup>5</sup> | 3 | 32 vCPU, 120 GB memory<sup>6</sup> | `n1-standard-32` | `m5.8xlarge` |
| Praefect<sup>5</sup> | 3 | 4 vCPU, 3.6 GB memory | `n1-highcpu-4` | `c5.xlarge` |
| Praefect PostgreSQL<sup>1</sup> | 1+ | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` |
| Object storage<sup>4</sup> | - | - | - | - |
**Footnotes:**
<!-- Disable ordered list rule https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md029---ordered-list-item-prefix -->
<!-- markdownlint-disable MD029 -->
1. Can be optionally run on reputable third-party external PaaS PostgreSQL solutions. See [Provide your own PostgreSQL instance](#provide-your-own-postgresql-instance) for more information.
2. Can be optionally run on reputable third-party external PaaS Redis solutions. See [Provide your own Redis instances](#provide-your-own-redis-instances) for more information.
- Redis is primarily single threaded and doesn't significantly benefit from an increase in CPU cores. For this size of architecture it's strongly recommended having separate Cache and Persistent instances as specified to achieve optimum performance.
3. Can be optionally run on reputable third-party load balancing services (LB PaaS). See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information.
4. Should be run on reputable Cloud Provider or Self Managed solutions. See [Configure the object storage](#configure-the-object-storage) for more information.
5. Gitaly Cluster provides the benefits of fault tolerance, but comes with additional complexity of setup and management.
Review the existing [technical limitations and considerations before deploying Gitaly Cluster](../gitaly/index.md#before-deploying-gitaly-cluster). If you want sharded Gitaly, use the same specs listed above for `Gitaly`.
6. Gitaly specifications are based on high percentiles of both usage patterns and repository sizes in good health.
However, if you have [large monorepos](index.md#large-monorepos) (larger than several gigabytes) or [additional workloads](index.md#additional-workloads) these can *significantly* impact Git and Gitaly performance and further adjustments will likely be required.
<!-- markdownlint-enable MD029 -->
NOTE:
For all PaaS solutions that involve configuring instances, it's recommended to implement a minimum of three nodes in three different availability zones to align with resilient cloud architecture practices.
```plantuml
@startuml 25k
skinparam linetype ortho
card "Kubernetes via Helm Charts" as kubernetes {
card "**External Load Balancer**" as elb #6a9be7
together {
collections "**Webservice**" as gitlab #32CD32
collections "**Sidekiq**" as sidekiq #ff8dd1
}
card "**Supporting Services**" as support
}
card "**Internal Load Balancer**" as ilb #9370DB
collections "**Consul** x3" as consul #e76a9b
card "Gitaly Cluster" as gitaly_cluster {
collections "**Praefect** x3" as praefect #FF8C00
collections "**Gitaly** x3" as gitaly #FF8C00
card "**Praefect PostgreSQL***\n//Non fault-tolerant//" as praefect_postgres #FF8C00
praefect -[#FF8C00]-> gitaly
praefect -[#FF8C00]> praefect_postgres
}
card "Database" as database {
collections "**PGBouncer** x3" as pgbouncer #4EA7FF
card "**PostgreSQL** (Primary)" as postgres_primary #4EA7FF
collections "**PostgreSQL** (Secondary) x2" as postgres_secondary #4EA7FF
pgbouncer -[#4EA7FF]-> postgres_primary
postgres_primary .[#4EA7FF]> postgres_secondary
}
card "redis" as redis {
collections "**Redis Persistent** x3" as redis_persistent #FF6347
collections "**Redis Cache** x3" as redis_cache #FF6347
redis_cache -[hidden]-> redis_persistent
}
cloud "**Object Storage**" as object_storage #white
elb -[#6a9be7]-> gitlab
elb -[hidden]-> sidekiq
elb -[hidden]-> support
gitlab -[#32CD32]--> ilb
gitlab -[#32CD32]r--> object_storage
gitlab -[#32CD32,norank]----> redis
gitlab -[#32CD32]----> database
sidekiq -[#ff8dd1]--> ilb
sidekiq -[#ff8dd1]r--> object_storage
sidekiq -[#ff8dd1,norank]----> redis
sidekiq .[#ff8dd1]----> database
ilb -[#9370DB]--> gitaly_cluster
ilb -[#9370DB]--> database
ilb -[hidden,norank]--> redis
consul .[#e76a9b]--> database
consul .[#e76a9b,norank]--> gitaly_cluster
consul .[#e76a9b]--> redis
@enduml
```
### Kubernetes component targets
The following section details the targets used for the GitLab components deployed in Kubernetes.
#### Webservice
Each Webservice pod (Puma and Workhorse) is recommended to be run with the following configuration:
- 4 Puma Workers
- 4 vCPU
- 5 GB memory (request)
- 7 GB memory (limit)
For 500 RPS or 25,000 users we recommend a total Puma worker count of around 140 so in turn it's recommended to run at
least 35 Webservice pods.
For further information on Webservice resource usage, see the Charts documentation on [Webservice resources](https://docs.gitlab.com/charts/charts/gitlab/webservice/#resources).
##### NGINX
It's also recommended deploying the NGINX controller pods across the Webservice nodes as a DaemonSet. This is to allow the controllers to scale dynamically with the Webservice pods they serve and take advantage of the higher network bandwidth larger machine types typically have.
This isn't a strict requirement. The NGINX controller pods can be deployed as desired as long as they have enough resources to handle the web traffic.
#### Sidekiq
Each Sidekiq pod is recommended to be run with the following configuration:
- 1 Sidekiq worker
- 900m vCPU
- 2 GB memory (request)
- 4 GB memory (limit)
Similar to the standard deployment above, an initial target of 14 Sidekiq workers has been used here.
Additional workers may be required depending on your specific workflow.
For further information on Sidekiq resource usage, see the Charts documentation on [Sidekiq resources](https://docs.gitlab.com/charts/charts/gitlab/sidekiq/#resources).
### Supporting
The Supporting Node Pool is designed to house all supporting deployments that don't need to be
on the Webservice and Sidekiq pools.
This includes various deployments related to the Cloud Provider's implementation and supporting
GitLab deployments such as [GitLab Shell](https://docs.gitlab.com/charts/charts/gitlab/gitlab-shell/).
If you wish to make any additional deployments such as Container Registry, Pages or Monitoring, it's recommended
to deploy these in this pool where possible and not in the Webservice or Sidekiq pools, as the Supporting pool has been designed
specifically to accommodate several additional deployments. However, if your deployments don't fit into the
pool as given, you can increase the node pool accordingly. Conversely, if the pool in your use case is over-provisioned you can reduce accordingly.
### Example config file
An example for the GitLab Helm Charts targeting the above 500 RPS or 25,000 reference architecture configuration [can be found in the Charts project](https://gitlab.com/gitlab-org/charts/gitlab/-/blob/master/examples/ref/25k.yaml).
<div align="right">
<a type="button" class="btn btn-default" href="#set-up-components">
Back to set up components <i class="fa fa-angle-double-up" aria-hidden="true"></i>
</a>
</div>
## Next steps
After following this guide you should now have a fresh GitLab environment with core functionality configured accordingly.
You may want to configure additional optional features of GitLab depending on your requirements. See [Steps after installing GitLab](../../install/next_steps.md) for more information.
NOTE:
Depending on your environment and requirements, additional hardware requirements or adjustments may be required to set up additional features as desired. Refer to the individual pages for more information.
|