[{"data":1,"prerenderedAt":2092},["ShallowReactive",2],{"/blog/improve-cd-workflows-helm-chart-registry":3,"navigation-en-us":1309,"banner-en-us":1737,"footer-en-us":1747,"blog-post-authors-en-us-Philip Welz":1989,"blog-related-posts-en-us-improve-cd-workflows-helm-chart-registry":2003,"blog-promotions-en-us":2028,"next-steps-en-us":2082},{"id":4,"title":5,"authors":6,"body":8,"category":1288,"date":1289,"description":1290,"extension":1291,"externalUrl":1292,"faq":1292,"featured":1293,"heroImage":1294,"meta":1295,"navigation":817,"path":1296,"seo":1297,"slug":1301,"stem":1302,"tags":1303,"template":1307,"updatedDate":1292,"__hash__":1308},"blogPosts/en-us/blog/improve-cd-workflows-helm-chart-registry.md","Get started with GitLab's Helm Package Registry",[7],"Philip Welz",{"type":9,"value":10,"toc":1277},"minimark",[11,15,20,56,82,87,96,99,108,111,114,339,342,494,501,523,527,530,533,546,564,575,700,708,711,731,735,738,747,762,765,768,772,788,795,874,878,887,974,977,1065,1069,1072,1151,1154,1233,1237,1251,1259,1273],[12,13,14],"p",{},"In our 14.1 release, we offered the ability to add Helm charts to the GitLab Package Registry. Here's everything you need to know to leverage application deployment with these new features.",[16,17,19],"h2",{"id":18},"the-role-of-container-images","The role of container images",[12,21,22,23,29,30,34,35,38,39,44,45,49,50,55],{},"The de-facto standard is to package applications into ",[24,25,28],"a",{"href":26,"rel":27},"https://github.com/opencontainers/image-spec",[],"OCI Images"," which are often just referred to as ",[31,32,33],"code",{},"container images"," and more often as ",[31,36,37],{},"Docker containers",". The ",[24,40,43],{"href":41,"rel":42},"https://opencontainers.org/",[],"Open Container Initiative"," was launched in 2015 by Docker and other companies to define industry standards around container image formats and runtimes. GitLab introduced an OCI conform ",[24,46,48],{"href":47},"/blog/gitlab-container-registry/","Container Registry"," with the release of ",[24,51,54],{"href":52,"rel":53},"https://docs.gitlab.com/releases/",[],"GitLab 8.8"," in May 2016.",[12,57,58,59,64,65,70,71,75,76,81],{},"Today, a common and widely adopted approach is to deploy applications with ",[24,60,63],{"href":61,"rel":62},"https://helm.sh/",[],"Helm charts"," to ",[24,66,69],{"href":67,"rel":68},"https://kubernetes.io/",[],"Kubernetes",". This will be covered in this blog together with the feature release in ",[24,72,74],{"href":52,"rel":73},[],"GitLab 14.1"," of adding Helm Charts to the ",[24,77,80],{"href":78,"rel":79},"https://docs.gitlab.com/user/packages/package_registry/",[],"GitLab Package Registry",".",[83,84,86],"h3",{"id":85},"install-software-to-kubernetes","Install software to Kubernetes",[12,88,89,90,95],{},"In the DevOps era, ",[24,91,94],{"href":92,"rel":93},"https://en.wikipedia.org/wiki/API",[],"APIs"," became incredibly popular, helping to drive demand for Kubernetes.",[12,97,98],{},"The core of Kubernetes' control plane is the API server. The API server exposes an HTTP REST API that lets end users, different parts of your cluster, and external components communicate with one another.",[12,100,101,102,107],{},"To interact with the API server we can use the command-line tool ",[24,103,106],{"href":104,"rel":105},"https://kubernetes.io/docs/reference/kubectl/overview/",[],"kubectl"," - although it would be also possible to use software development kits (SDKs) or any client that understands REST like curl that was released 1997.",[12,109,110],{},"But which data format is best to use?",[12,112,113],{},"Modern APIs most likely use JSON. JSON is a human-readable format that provides provide access to machine-readable data. Here is an example for Kubernetes:",[115,116,121],"pre",{"className":117,"code":118,"language":119,"meta":120,"style":120},"language-json shiki shiki-themes github-light","{\n    \"kind\": \"Pod\",\n    \"apiVersion\": \"v1\",\n    \"metadata\": {\n        \"name\": \"nginx\",\n        \"creationTimestamp\": null,\n        \"labels\": {\n            \"run\": \"nginx\"\n        }\n    },\n    \"spec\": {\n        \"containers\": [\n            {\n                \"name\": \"nginx\",\n                \"image\": \"nginx\",\n                \"resources\": {}\n            }\n        ],\n        \"restartPolicy\": \"Always\",\n        \"dnsPolicy\": \"ClusterFirst\"\n    },\n    \"status\": {}\n}\n","json","",[31,122,123,132,149,162,171,184,197,205,216,222,228,236,245,251,263,275,284,290,296,309,320,325,333],{"__ignoreMap":120},[124,125,128],"span",{"class":126,"line":127},"line",1,[124,129,131],{"class":130},"sgsFI","{\n",[124,133,135,139,142,146],{"class":126,"line":134},2,[124,136,138],{"class":137},"sYu0t","    \"kind\"",[124,140,141],{"class":130},": ",[124,143,145],{"class":144},"sYBdl","\"Pod\"",[124,147,148],{"class":130},",\n",[124,150,152,155,157,160],{"class":126,"line":151},3,[124,153,154],{"class":137},"    \"apiVersion\"",[124,156,141],{"class":130},[124,158,159],{"class":144},"\"v1\"",[124,161,148],{"class":130},[124,163,165,168],{"class":126,"line":164},4,[124,166,167],{"class":137},"    \"metadata\"",[124,169,170],{"class":130},": {\n",[124,172,174,177,179,182],{"class":126,"line":173},5,[124,175,176],{"class":137},"        \"name\"",[124,178,141],{"class":130},[124,180,181],{"class":144},"\"nginx\"",[124,183,148],{"class":130},[124,185,187,190,192,195],{"class":126,"line":186},6,[124,188,189],{"class":137},"        \"creationTimestamp\"",[124,191,141],{"class":130},[124,193,194],{"class":137},"null",[124,196,148],{"class":130},[124,198,200,203],{"class":126,"line":199},7,[124,201,202],{"class":137},"        \"labels\"",[124,204,170],{"class":130},[124,206,208,211,213],{"class":126,"line":207},8,[124,209,210],{"class":137},"            \"run\"",[124,212,141],{"class":130},[124,214,215],{"class":144},"\"nginx\"\n",[124,217,219],{"class":126,"line":218},9,[124,220,221],{"class":130},"        }\n",[124,223,225],{"class":126,"line":224},10,[124,226,227],{"class":130},"    },\n",[124,229,231,234],{"class":126,"line":230},11,[124,232,233],{"class":137},"    \"spec\"",[124,235,170],{"class":130},[124,237,239,242],{"class":126,"line":238},12,[124,240,241],{"class":137},"        \"containers\"",[124,243,244],{"class":130},": [\n",[124,246,248],{"class":126,"line":247},13,[124,249,250],{"class":130},"            {\n",[124,252,254,257,259,261],{"class":126,"line":253},14,[124,255,256],{"class":137},"                \"name\"",[124,258,141],{"class":130},[124,260,181],{"class":144},[124,262,148],{"class":130},[124,264,266,269,271,273],{"class":126,"line":265},15,[124,267,268],{"class":137},"                \"image\"",[124,270,141],{"class":130},[124,272,181],{"class":144},[124,274,148],{"class":130},[124,276,278,281],{"class":126,"line":277},16,[124,279,280],{"class":137},"                \"resources\"",[124,282,283],{"class":130},": {}\n",[124,285,287],{"class":126,"line":286},17,[124,288,289],{"class":130},"            }\n",[124,291,293],{"class":126,"line":292},18,[124,294,295],{"class":130},"        ],\n",[124,297,299,302,304,307],{"class":126,"line":298},19,[124,300,301],{"class":137},"        \"restartPolicy\"",[124,303,141],{"class":130},[124,305,306],{"class":144},"\"Always\"",[124,308,148],{"class":130},[124,310,312,315,317],{"class":126,"line":311},20,[124,313,314],{"class":137},"        \"dnsPolicy\"",[124,316,141],{"class":130},[124,318,319],{"class":144},"\"ClusterFirst\"\n",[124,321,323],{"class":126,"line":322},21,[124,324,227],{"class":130},[124,326,328,331],{"class":126,"line":327},22,[124,329,330],{"class":137},"    \"status\"",[124,332,283],{"class":130},[124,334,336],{"class":126,"line":335},23,[124,337,338],{"class":130},"}\n",[12,340,341],{},"One downside of JSON is that comments are not supported. That is one several reasons why YAML stepped in and took the spot as the de-facto language to use for declarative configurations. The Kubernetes API transforms YAML to JSON behind the scenes. As you can easily convert back and forth between both, YAML tends to be more user-friendly. Nginx example Pod in YAML:",[115,343,347],{"className":344,"code":345,"language":346,"meta":120,"style":120},"language-yaml shiki shiki-themes github-light","apiVersion: v1\nkind: Pod\nmetadata:\n  creationTimestamp: null\n  labels:\n    run: nginx\n  name: nginx\nspec:\n  Containers:\n  # NOTE: If no tag is specified latest will be used\n  - image: nginx\n    name: nginx\n    # TODO\n    resources: {}\n  dnsPolicy: ClusterFirst\n  restartPolicy: Always\nstatus: {}\n","yaml",[31,348,349,360,370,378,388,395,405,414,421,428,434,446,455,460,467,477,487],{"__ignoreMap":120},[124,350,351,355,357],{"class":126,"line":127},[124,352,354],{"class":353},"shJU0","apiVersion",[124,356,141],{"class":130},[124,358,359],{"class":144},"v1\n",[124,361,362,365,367],{"class":126,"line":134},[124,363,364],{"class":353},"kind",[124,366,141],{"class":130},[124,368,369],{"class":144},"Pod\n",[124,371,372,375],{"class":126,"line":151},[124,373,374],{"class":353},"metadata",[124,376,377],{"class":130},":\n",[124,379,380,383,385],{"class":126,"line":164},[124,381,382],{"class":353},"  creationTimestamp",[124,384,141],{"class":130},[124,386,387],{"class":137},"null\n",[124,389,390,393],{"class":126,"line":173},[124,391,392],{"class":353},"  labels",[124,394,377],{"class":130},[124,396,397,400,402],{"class":126,"line":186},[124,398,399],{"class":353},"    run",[124,401,141],{"class":130},[124,403,404],{"class":144},"nginx\n",[124,406,407,410,412],{"class":126,"line":199},[124,408,409],{"class":353},"  name",[124,411,141],{"class":130},[124,413,404],{"class":144},[124,415,416,419],{"class":126,"line":207},[124,417,418],{"class":353},"spec",[124,420,377],{"class":130},[124,422,423,426],{"class":126,"line":218},[124,424,425],{"class":353},"  Containers",[124,427,377],{"class":130},[124,429,430],{"class":126,"line":224},[124,431,433],{"class":432},"sAwPA","  # NOTE: If no tag is specified latest will be used\n",[124,435,436,439,442,444],{"class":126,"line":230},[124,437,438],{"class":130},"  - ",[124,440,441],{"class":353},"image",[124,443,141],{"class":130},[124,445,404],{"class":144},[124,447,448,451,453],{"class":126,"line":238},[124,449,450],{"class":353},"    name",[124,452,141],{"class":130},[124,454,404],{"class":144},[124,456,457],{"class":126,"line":247},[124,458,459],{"class":432},"    # TODO\n",[124,461,462,465],{"class":126,"line":253},[124,463,464],{"class":353},"    resources",[124,466,283],{"class":130},[124,468,469,472,474],{"class":126,"line":265},[124,470,471],{"class":353},"  dnsPolicy",[124,473,141],{"class":130},[124,475,476],{"class":144},"ClusterFirst\n",[124,478,479,482,484],{"class":126,"line":277},[124,480,481],{"class":353},"  restartPolicy",[124,483,141],{"class":130},[124,485,486],{"class":144},"Always\n",[124,488,489,492],{"class":126,"line":286},[124,490,491],{"class":353},"status",[124,493,283],{"class":130},[12,495,496,497,500],{},"Now you are ready to save our YAML code in a file called ",[31,498,499],{},"nginx.yaml"," and deploy it into Kubernetes:",[115,502,506],{"className":503,"code":504,"language":505,"meta":120,"style":120},"language-shell shiki shiki-themes github-light","$ kubectl apply --filename=nginx.yaml\n","shell",[31,507,508],{"__ignoreMap":120},[124,509,510,514,517,520],{"class":126,"line":127},[124,511,513],{"class":512},"s7eDp","$",[124,515,516],{"class":144}," kubectl",[124,518,519],{"class":144}," apply",[124,521,522],{"class":137}," --filename=nginx.yaml\n",[83,524,526],{"id":525},"create-a-helm-chart","Create a Helm chart",[12,528,529],{},"Applying YAML configuration files can get overwhelming, especially when needing to deploy into several environments or wanting to version the manifests. It is also cumbersome to maintain plain YAML files for more complex deployments which can easily extend to more than 1000 lines per file.",[12,531,532],{},"Instead, how about using a format that packages our applications and makes them easily reproducible with templates? How about adding our own versioning scheme to this packaged application? How about deploying the same version with a few lines of code to multiple environments? This all comes with Helm.",[12,534,535,536,541,542,545],{},"To create a Helm package you have to ensure that the Helm CLI is ",[24,537,540],{"href":538,"rel":539},"https://helm.sh/docs/intro/install/",[],"installed"," on your system (example with Homebrew on macOS: ",[31,543,544],{},"brew install helm",").",[115,547,549],{"className":503,"code":548,"language":505,"meta":120,"style":120},"$ helm create nginx\n",[31,550,551],{"__ignoreMap":120},[124,552,553,555,558,561],{"class":126,"line":127},[124,554,513],{"class":512},[124,556,557],{"class":144}," helm",[124,559,560],{"class":144}," create",[124,562,563],{"class":144}," nginx\n",[12,565,566,567,570,571,574],{},"Inspect the created Helm boilerplate files with ",[31,568,569],{},"ls -lR"," or ",[31,572,573],{},"tree"," on the CLI. This Helm chart can also be tested in a sandbox environment to verify it is operational.",[115,576,578],{"className":503,"code":577,"language":505,"meta":120,"style":120},".\n├── Chart.yaml\n├── charts\n├── templates\n│   ├── NOTES.txt\n│   ├── _helpers.tpl\n│   ├── deployment.yaml\n│   ├── hpa.yaml\n│   ├── ingress.yaml\n│   ├── service.yaml\n│   ├── serviceaccount.yaml\n│   └── tests\n│       └── test-connection.yaml\n└── values.yaml\n",[31,579,580,585,593,600,607,618,627,636,645,654,663,672,682,692],{"__ignoreMap":120},[124,581,582],{"class":126,"line":127},[124,583,584],{"class":137},".\n",[124,586,587,590],{"class":126,"line":134},[124,588,589],{"class":512},"├──",[124,591,592],{"class":144}," Chart.yaml\n",[124,594,595,597],{"class":126,"line":151},[124,596,589],{"class":512},[124,598,599],{"class":144}," charts\n",[124,601,602,604],{"class":126,"line":164},[124,603,589],{"class":512},[124,605,606],{"class":144}," templates\n",[124,608,609,612,615],{"class":126,"line":173},[124,610,611],{"class":512},"│",[124,613,614],{"class":144},"   ├──",[124,616,617],{"class":144}," NOTES.txt\n",[124,619,620,622,624],{"class":126,"line":186},[124,621,611],{"class":512},[124,623,614],{"class":144},[124,625,626],{"class":144}," _helpers.tpl\n",[124,628,629,631,633],{"class":126,"line":199},[124,630,611],{"class":512},[124,632,614],{"class":144},[124,634,635],{"class":144}," deployment.yaml\n",[124,637,638,640,642],{"class":126,"line":207},[124,639,611],{"class":512},[124,641,614],{"class":144},[124,643,644],{"class":144}," hpa.yaml\n",[124,646,647,649,651],{"class":126,"line":218},[124,648,611],{"class":512},[124,650,614],{"class":144},[124,652,653],{"class":144}," ingress.yaml\n",[124,655,656,658,660],{"class":126,"line":224},[124,657,611],{"class":512},[124,659,614],{"class":144},[124,661,662],{"class":144}," service.yaml\n",[124,664,665,667,669],{"class":126,"line":230},[124,666,611],{"class":512},[124,668,614],{"class":144},[124,670,671],{"class":144}," serviceaccount.yaml\n",[124,673,674,676,679],{"class":126,"line":238},[124,675,611],{"class":512},[124,677,678],{"class":144},"   └──",[124,680,681],{"class":144}," tests\n",[124,683,684,686,689],{"class":126,"line":247},[124,685,611],{"class":512},[124,687,688],{"class":144},"       └──",[124,690,691],{"class":144}," test-connection.yaml\n",[124,693,694,697],{"class":126,"line":253},[124,695,696],{"class":512},"└──",[124,698,699],{"class":144}," values.yaml\n",[12,701,702,703,81],{},"NOTE: You can read more about the starter Chart ",[24,704,707],{"href":705,"rel":706},"https://helm.sh/docs/chart_template_guide/getting_started/",[],"here",[12,709,710],{},"Kindly Helm creates a starter chart directory along with the common files and directories used in a chart with NGINX as an example. We again can install this into our Kubernetes cluster:",[115,712,714],{"className":503,"code":713,"language":505,"meta":120,"style":120},"$ helm install nginx .\n",[31,715,716],{"__ignoreMap":120},[124,717,718,720,722,725,728],{"class":126,"line":127},[124,719,513],{"class":512},[124,721,557],{"class":144},[124,723,724],{"class":144}," install",[124,726,727],{"class":144}," nginx",[124,729,730],{"class":144}," .\n",[83,732,734],{"id":733},"package-distribution","Package Distribution",[12,736,737],{},"Thus far, we have learned that applications are packaged in containers and are installed using a Helm chart. Both methods require central distribution storage that is publicly accessible, or accessible in your local network environment where the Kubernetes clusters are running.",[12,739,740,741,746],{},"The Helm documentation provides insights on ",[24,742,745],{"href":743,"rel":744},"https://helm.sh/docs/topics/registries/",[],"running your own Helm registry",", similar to hosting your own Docker container registry.",[12,748,749,750,755,756,761],{},"What if we could avoid Do It Yourself DevOps and have both containers and Helm charts in one central DevOps platform? After maturing the ",[24,751,754],{"href":752,"rel":753},"https://docs.gitlab.com/user/packages/container_registry/",[],"container registry in GitLab",", community contributors helped add the ",[24,757,760],{"href":758,"rel":759},"https://docs.gitlab.com/user/packages/helm_repository/",[],"Helm chart registry"," in 14.1.",[12,763,764],{},"Building the container image and Helm chart is part of the CI/CD pipeline stages and jobs. The missing bit is the automated production deployment using Helm charts in your Kubernetes cluster.",[12,766,767],{},"An additional benefit in CI/CD is reusing the authentication mechanism, and working in the same trust environment with security jobs before actually uploading and publishing any containers and charts.",[83,769,771],{"id":770},"build-the-helm-chart","Build the Helm Chart",[115,773,775],{"className":503,"code":774,"language":505,"meta":120,"style":120},"$ helm package nginx\n",[31,776,777],{"__ignoreMap":120},[124,778,779,781,783,786],{"class":126,"line":127},[124,780,513],{"class":512},[124,782,557],{"class":144},[124,784,785],{"class":144}," package",[124,787,563],{"class":144},[12,789,790,791,794],{},"The command creates a new tar.gz archive ready to upload. Before doing so, you can inspect the archive with the ",[31,792,793],{},"tar"," command to verify its content.",[115,796,798],{"className":503,"code":797,"language":505,"meta":120,"style":120},"$ tar ztf nginx-0.1.0.tgz\n\nnginx/Chart.yaml\nnginx/values.yaml\nnginx/templates/NOTES.txt\nnginx/templates/_helpers.tpl\nnginx/templates/deployment.yaml\nnginx/templates/hpa.yaml\nnginx/templates/ingress.yaml\nnginx/templates/service.yaml\nnginx/templates/serviceaccount.yaml\nnginx/templates/tests/test-connection.yaml\nnginx/.helmignore\n",[31,799,800,813,819,824,829,834,839,844,849,854,859,864,869],{"__ignoreMap":120},[124,801,802,804,807,810],{"class":126,"line":127},[124,803,513],{"class":512},[124,805,806],{"class":144}," tar",[124,808,809],{"class":144}," ztf",[124,811,812],{"class":144}," nginx-0.1.0.tgz\n",[124,814,815],{"class":126,"line":134},[124,816,818],{"emptyLinePlaceholder":817},true,"\n",[124,820,821],{"class":126,"line":151},[124,822,823],{"class":512},"nginx/Chart.yaml\n",[124,825,826],{"class":126,"line":164},[124,827,828],{"class":512},"nginx/values.yaml\n",[124,830,831],{"class":126,"line":173},[124,832,833],{"class":512},"nginx/templates/NOTES.txt\n",[124,835,836],{"class":126,"line":186},[124,837,838],{"class":512},"nginx/templates/_helpers.tpl\n",[124,840,841],{"class":126,"line":199},[124,842,843],{"class":512},"nginx/templates/deployment.yaml\n",[124,845,846],{"class":126,"line":207},[124,847,848],{"class":512},"nginx/templates/hpa.yaml\n",[124,850,851],{"class":126,"line":218},[124,852,853],{"class":512},"nginx/templates/ingress.yaml\n",[124,855,856],{"class":126,"line":224},[124,857,858],{"class":512},"nginx/templates/service.yaml\n",[124,860,861],{"class":126,"line":230},[124,862,863],{"class":512},"nginx/templates/serviceaccount.yaml\n",[124,865,866],{"class":126,"line":238},[124,867,868],{"class":512},"nginx/templates/tests/test-connection.yaml\n",[124,870,871],{"class":126,"line":247},[124,872,873],{"class":512},"nginx/.helmignore\n",[83,875,877],{"id":876},"push-the-helm-chart-to-the-registry","Push the Helm chart to the registry",[12,879,880,881,886],{},"With the ",[24,882,885],{"href":883,"rel":884},"https://github.com/chartmuseum/helm-push/#readme",[],"helm-push"," plugin for Helm we can now upload the chart to the GitLab Helm Package Registry:",[115,888,890],{"className":503,"code":889,"language":505,"meta":120,"style":120},"$ helm repo add --username \u003Cusername> --password \u003Cpersonal_access_token> \u003CREGISTRY_NAME> https://gitlab.com/api/v4/projects/\u003Cproject_id>/packages/helm/stable\n$ helm push nginx-0.1.0.tgz nginx\n",[31,891,892,960],{"__ignoreMap":120},[124,893,894,896,898,901,904,907,911,914,917,920,923,925,928,931,933,935,938,941,943,946,949,952,955,957],{"class":126,"line":127},[124,895,513],{"class":512},[124,897,557],{"class":144},[124,899,900],{"class":144}," repo",[124,902,903],{"class":144}," add",[124,905,906],{"class":137}," --username",[124,908,910],{"class":909},"sD7c4"," \u003C",[124,912,913],{"class":144},"usernam",[124,915,916],{"class":130},"e",[124,918,919],{"class":909},">",[124,921,922],{"class":137}," --password",[124,924,910],{"class":909},[124,926,927],{"class":144},"personal_access_toke",[124,929,930],{"class":130},"n",[124,932,919],{"class":909},[124,934,910],{"class":909},[124,936,937],{"class":144},"REGISTRY_NAM",[124,939,940],{"class":130},"E",[124,942,919],{"class":909},[124,944,945],{"class":144}," https://gitlab.com/api/v4/projects/",[124,947,948],{"class":909},"\u003C",[124,950,951],{"class":144},"project_i",[124,953,954],{"class":130},"d",[124,956,919],{"class":909},[124,958,959],{"class":144},"/packages/helm/stable\n",[124,961,962,964,966,969,972],{"class":126,"line":134},[124,963,513],{"class":512},[124,965,557],{"class":144},[124,967,968],{"class":144}," push",[124,970,971],{"class":144}," nginx-0.1.0.tgz",[124,973,563],{"class":144},[12,975,976],{},"This step should be automated for a production-ready deployment with a GitLab CI/CD job.",[115,978,980],{"className":344,"code":979,"language":346,"meta":120,"style":120},"default:\n  image: dtzar/helm-kubectl\n  before_script:\n    - 'helm repo add --username gitlab-ci-token --password ${CI_JOB_TOKEN} ${CI_PROJECT_NAME} ${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/helm/stable'\nstages:\n  - upload\nupload:\n  stage: upload\n  script:\n    - 'helm plugin install https://github.com/chartmuseum/helm-push.git'\n    - 'helm push ./charts/podtatoserver-0.1.0.tgz ${CI_PROJECT_NAME}'\n\n",[31,981,982,989,999,1006,1014,1021,1028,1035,1044,1051,1058],{"__ignoreMap":120},[124,983,984,987],{"class":126,"line":127},[124,985,986],{"class":353},"default",[124,988,377],{"class":130},[124,990,991,994,996],{"class":126,"line":134},[124,992,993],{"class":353},"  image",[124,995,141],{"class":130},[124,997,998],{"class":144},"dtzar/helm-kubectl\n",[124,1000,1001,1004],{"class":126,"line":151},[124,1002,1003],{"class":353},"  before_script",[124,1005,377],{"class":130},[124,1007,1008,1011],{"class":126,"line":164},[124,1009,1010],{"class":130},"    - ",[124,1012,1013],{"class":144},"'helm repo add --username gitlab-ci-token --password ${CI_JOB_TOKEN} ${CI_PROJECT_NAME} ${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/helm/stable'\n",[124,1015,1016,1019],{"class":126,"line":173},[124,1017,1018],{"class":353},"stages",[124,1020,377],{"class":130},[124,1022,1023,1025],{"class":126,"line":186},[124,1024,438],{"class":130},[124,1026,1027],{"class":144},"upload\n",[124,1029,1030,1033],{"class":126,"line":199},[124,1031,1032],{"class":353},"upload",[124,1034,377],{"class":130},[124,1036,1037,1040,1042],{"class":126,"line":207},[124,1038,1039],{"class":353},"  stage",[124,1041,141],{"class":130},[124,1043,1027],{"class":144},[124,1045,1046,1049],{"class":126,"line":218},[124,1047,1048],{"class":353},"  script",[124,1050,377],{"class":130},[124,1052,1053,1055],{"class":126,"line":224},[124,1054,1010],{"class":130},[124,1056,1057],{"class":144},"'helm plugin install https://github.com/chartmuseum/helm-push.git'\n",[124,1059,1060,1062],{"class":126,"line":230},[124,1061,1010],{"class":130},[124,1063,1064],{"class":144},"'helm push ./charts/podtatoserver-0.1.0.tgz ${CI_PROJECT_NAME}'\n",[83,1066,1068],{"id":1067},"install-the-helm-chart","Install the Helm chart",[12,1070,1071],{},"First, add the Helm chart registry to your local CLI configuration and test the manual installation.",[115,1073,1075],{"className":503,"code":1074,"language":505,"meta":120,"style":120},"$ helm repo add --username \u003Cusername> --password \u003Cpersonal_access_token> \u003CREGISTRY_NAME> https://gitlab.com/api/v4/projects/\u003Cproject_id>/packages/helm/stable\n$ helm install --name nginx \u003CREGISTRY_NAME>/nginx\n",[31,1076,1077,1127],{"__ignoreMap":120},[124,1078,1079,1081,1083,1085,1087,1089,1091,1093,1095,1097,1099,1101,1103,1105,1107,1109,1111,1113,1115,1117,1119,1121,1123,1125],{"class":126,"line":127},[124,1080,513],{"class":512},[124,1082,557],{"class":144},[124,1084,900],{"class":144},[124,1086,903],{"class":144},[124,1088,906],{"class":137},[124,1090,910],{"class":909},[124,1092,913],{"class":144},[124,1094,916],{"class":130},[124,1096,919],{"class":909},[124,1098,922],{"class":137},[124,1100,910],{"class":909},[124,1102,927],{"class":144},[124,1104,930],{"class":130},[124,1106,919],{"class":909},[124,1108,910],{"class":909},[124,1110,937],{"class":144},[124,1112,940],{"class":130},[124,1114,919],{"class":909},[124,1116,945],{"class":144},[124,1118,948],{"class":909},[124,1120,951],{"class":144},[124,1122,954],{"class":130},[124,1124,919],{"class":909},[124,1126,959],{"class":144},[124,1128,1129,1131,1133,1135,1138,1140,1142,1144,1146,1148],{"class":126,"line":134},[124,1130,513],{"class":512},[124,1132,557],{"class":144},[124,1134,724],{"class":144},[124,1136,1137],{"class":137}," --name",[124,1139,727],{"class":144},[124,1141,910],{"class":909},[124,1143,937],{"class":144},[124,1145,940],{"class":130},[124,1147,919],{"class":909},[124,1149,1150],{"class":144},"/nginx\n",[12,1152,1153],{},"Once it works, you can continue with adding an automated installation job into the CI/CD pipeline.",[115,1155,1157],{"className":344,"code":1156,"language":346,"meta":120,"style":120},"default:\n  image: alpine/helm\n  before_script:\n    - 'helm repo add --username gitlab-ci-token --password ${CI_JOB_TOKEN} ${CI_PROJECT_NAME} ${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/helm/stable'\nstages:\n  - install\nupload:\n  stage: install\n  script:\n    - 'helm repo update'\n    - 'helm install --name nginx ${CI_PROJECT_NAME}/nginx'\n\n",[31,1158,1159,1165,1174,1180,1186,1192,1199,1205,1213,1219,1226],{"__ignoreMap":120},[124,1160,1161,1163],{"class":126,"line":127},[124,1162,986],{"class":353},[124,1164,377],{"class":130},[124,1166,1167,1169,1171],{"class":126,"line":134},[124,1168,993],{"class":353},[124,1170,141],{"class":130},[124,1172,1173],{"class":144},"alpine/helm\n",[124,1175,1176,1178],{"class":126,"line":151},[124,1177,1003],{"class":353},[124,1179,377],{"class":130},[124,1181,1182,1184],{"class":126,"line":164},[124,1183,1010],{"class":130},[124,1185,1013],{"class":144},[124,1187,1188,1190],{"class":126,"line":173},[124,1189,1018],{"class":353},[124,1191,377],{"class":130},[124,1193,1194,1196],{"class":126,"line":186},[124,1195,438],{"class":130},[124,1197,1198],{"class":144},"install\n",[124,1200,1201,1203],{"class":126,"line":199},[124,1202,1032],{"class":353},[124,1204,377],{"class":130},[124,1206,1207,1209,1211],{"class":126,"line":207},[124,1208,1039],{"class":353},[124,1210,141],{"class":130},[124,1212,1198],{"class":144},[124,1214,1215,1217],{"class":126,"line":218},[124,1216,1048],{"class":353},[124,1218,377],{"class":130},[124,1220,1221,1223],{"class":126,"line":224},[124,1222,1010],{"class":130},[124,1224,1225],{"class":144},"'helm repo update'\n",[124,1227,1228,1230],{"class":126,"line":230},[124,1229,1010],{"class":130},[124,1231,1232],{"class":144},"'helm install --name nginx ${CI_PROJECT_NAME}/nginx'\n",[83,1234,1236],{"id":1235},"complete-your-devops-lifecycle","Complete your DevOps lifecycle",[12,1238,1239,1240,1245,1246,81],{},"You can learn more about the newest GitLab registries for Helm and Terraform in this ",[24,1241,1244],{"href":1242,"rel":1243},"https://everyonecancontribute.com/post/2021-07-28-cafe-40-terraform-helm-gitlab-registry/",[],"#EveryoneCanContribute cafe session"," and inspect the ",[24,1247,1250],{"href":1248,"rel":1249},"https://gitlab.com/everyonecancontribute/kubernetes/civo-k3s",[],"deployment repository",[12,1252,1253,1254,81],{},"Try the Helm chart registry and share your workflows. Are there any features missing to complete your DevOps lifecycle? Let us know ",[24,1255,1258],{"href":1256,"rel":1257},"https://discord.gg/qgQWhD6wWV",[],"on Discord",[12,1260,1261,1262,1267,1268],{},"Cover image by ",[24,1263,1266],{"href":1264,"rel":1265},"https://unsplash.com/@jbcreate_",[],"Joseph Barrientos"," on ",[24,1269,1272],{"href":1270,"rel":1271},"https://unsplash.com/photos/eUMEWE-7Ewg",[],"Unsplash",[1274,1275,1276],"style",{},"html pre.shiki code .sgsFI, html code.shiki .sgsFI{--shiki-default:#24292E}html pre.shiki code .sYu0t, html code.shiki .sYu0t{--shiki-default:#005CC5}html pre.shiki code .sYBdl, html code.shiki .sYBdl{--shiki-default:#032F62}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .shJU0, html code.shiki .shJU0{--shiki-default:#22863A}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html pre.shiki code .s7eDp, html code.shiki .s7eDp{--shiki-default:#6F42C1}html pre.shiki code .sD7c4, html code.shiki .sD7c4{--shiki-default:#D73A49}",{"title":120,"searchDepth":134,"depth":134,"links":1278},[1279],{"id":18,"depth":134,"text":19,"children":1280},[1281,1282,1283,1284,1285,1286,1287],{"id":85,"depth":151,"text":86},{"id":525,"depth":151,"text":526},{"id":733,"depth":151,"text":734},{"id":770,"depth":151,"text":771},{"id":876,"depth":151,"text":877},{"id":1067,"depth":151,"text":1068},{"id":1235,"depth":151,"text":1236},"devsecops","2021-10-18","Improve CD workflows and speed up application deployment using our new Helm Package Registry.","md",null,false,"https://res.cloudinary.com/about-gitlab-com/image/upload/v1749668078/Blog/Hero%20Images/cover-image-helm-registry.jpg",{},"/en-us/blog/improve-cd-workflows-helm-chart-registry",{"title":5,"description":1290,"ogTitle":5,"ogDescription":1290,"noIndex":1293,"ogImage":1294,"ogUrl":1298,"ogSiteName":1299,"ogType":1300,"canonicalUrls":1298},"https://about.gitlab.com/blog/improve-cd-workflows-helm-chart-registry","https://about.gitlab.com","article","improve-cd-workflows-helm-chart-registry","en-us/blog/improve-cd-workflows-helm-chart-registry",[1304,1305,1306],"DevOps","CD","kubernetes","BlogPost","09tc1Yu4mTrqK7x-DvnOF6hZlyCdPnMApPMDQW5qPts",{"logo":1310,"freeTrial":1315,"sales":1320,"login":1325,"items":1330,"search":1657,"minimal":1688,"duo":1707,"switchNav":1716,"pricingDeployment":1727},{"config":1311},{"href":1312,"dataGaName":1313,"dataGaLocation":1314},"/","gitlab logo","header",{"text":1316,"config":1317},"Get free trial",{"href":1318,"dataGaName":1319,"dataGaLocation":1314},"https://gitlab.com/-/trial_registrations/new?glm_source=about.gitlab.com&glm_content=default-saas-trial/","free trial",{"text":1321,"config":1322},"Request a demo",{"href":1323,"dataGaName":1324,"dataGaLocation":1314},"/sales/?contact-topic=request-demo","sales",{"text":1326,"config":1327},"Sign in",{"href":1328,"dataGaName":1329,"dataGaLocation":1314},"https://gitlab.com/users/sign_in/","sign in",[1331,1360,1460,1465,1579,1635],{"text":1332,"config":1333,"menu":1335},"Platform",{"dataNavLevelOne":1334},"platform",{"type":1336,"columns":1337},"cards",[1338,1344,1352],{"title":1332,"description":1339,"link":1340},"The intelligent orchestration platform for DevSecOps",{"text":1341,"config":1342},"Explore our Platform",{"href":1343,"dataGaName":1334,"dataGaLocation":1314},"/platform/",{"title":1345,"description":1346,"link":1347},"GitLab Duo Agent Platform","Agentic AI for the entire software lifecycle",{"text":1348,"config":1349},"Meet GitLab Duo",{"href":1350,"dataGaName":1351,"dataGaLocation":1314},"/gitlab-duo-agent-platform/","gitlab duo agent platform",{"title":1353,"description":1354,"link":1355},"Why GitLab","See the top reasons enterprises choose GitLab",{"text":1356,"config":1357},"Learn more",{"href":1358,"dataGaName":1359,"dataGaLocation":1314},"/why-gitlab/","why gitlab",{"text":1361,"left":817,"config":1362,"menu":1364},"Product",{"dataNavLevelOne":1363},"solutions",{"type":1365,"link":1366,"columns":1370,"feature":1439},"lists",{"text":1367,"config":1368},"View all Solutions",{"href":1369,"dataGaName":1363,"dataGaLocation":1314},"/solutions/",[1371,1395,1418],{"title":1372,"description":1373,"link":1374,"items":1379},"Automation","CI/CD and automation to accelerate deployment",{"config":1375},{"icon":1376,"href":1377,"dataGaName":1378,"dataGaLocation":1314},"AutomatedCodeAlt","/solutions/delivery-automation/","automated software delivery",[1380,1384,1387,1391],{"text":1381,"config":1382},"CI/CD",{"href":1383,"dataGaLocation":1314,"dataGaName":1381},"/solutions/continuous-integration/",{"text":1345,"config":1385},{"href":1350,"dataGaLocation":1314,"dataGaName":1386},"gitlab duo agent platform - product menu",{"text":1388,"config":1389},"Source Code Management",{"href":1390,"dataGaLocation":1314,"dataGaName":1388},"/solutions/source-code-management/",{"text":1392,"config":1393},"Automated Software Delivery",{"href":1377,"dataGaLocation":1314,"dataGaName":1394},"Automated software delivery",{"title":1396,"description":1397,"link":1398,"items":1403},"Security","Deliver code faster without compromising security",{"config":1399},{"href":1400,"dataGaName":1401,"dataGaLocation":1314,"icon":1402},"/solutions/application-security-testing/","security and compliance","ShieldCheckLight",[1404,1408,1413],{"text":1405,"config":1406},"Application Security Testing",{"href":1400,"dataGaName":1407,"dataGaLocation":1314},"Application security testing",{"text":1409,"config":1410},"Software Supply Chain Security",{"href":1411,"dataGaLocation":1314,"dataGaName":1412},"/solutions/supply-chain/","Software supply chain security",{"text":1414,"config":1415},"Software Compliance",{"href":1416,"dataGaName":1417,"dataGaLocation":1314},"/solutions/software-compliance/","software compliance",{"title":1419,"link":1420,"items":1425},"Measurement",{"config":1421},{"icon":1422,"href":1423,"dataGaName":1424,"dataGaLocation":1314},"DigitalTransformation","/solutions/visibility-measurement/","visibility and measurement",[1426,1430,1434],{"text":1427,"config":1428},"Visibility & Measurement",{"href":1423,"dataGaLocation":1314,"dataGaName":1429},"Visibility and Measurement",{"text":1431,"config":1432},"Value Stream Management",{"href":1433,"dataGaLocation":1314,"dataGaName":1431},"/solutions/value-stream-management/",{"text":1435,"config":1436},"Analytics & Insights",{"href":1437,"dataGaLocation":1314,"dataGaName":1438},"/solutions/analytics-and-insights/","Analytics and insights",{"title":1440,"type":1365,"items":1441},"GitLab for",[1442,1448,1454],{"text":1443,"config":1444},"Enterprise",{"icon":1445,"href":1446,"dataGaLocation":1314,"dataGaName":1447},"Building","/enterprise/","enterprise",{"text":1449,"config":1450},"Small Business",{"icon":1451,"href":1452,"dataGaLocation":1314,"dataGaName":1453},"Work","/small-business/","small business",{"text":1455,"config":1456},"Public Sector",{"icon":1457,"href":1458,"dataGaLocation":1314,"dataGaName":1459},"Organization","/solutions/public-sector/","public sector",{"text":1461,"config":1462},"Pricing",{"href":1463,"dataGaName":1464,"dataGaLocation":1314,"dataNavLevelOne":1464},"/pricing/","pricing",{"text":1466,"config":1467,"menu":1469},"Resources",{"dataNavLevelOne":1468},"resources",{"type":1365,"link":1470,"columns":1474,"feature":1568},{"text":1471,"config":1472},"View all resources",{"href":1473,"dataGaName":1468,"dataGaLocation":1314},"/resources/",[1475,1508,1535],{"title":1476,"items":1477},"Getting started",[1478,1483,1488,1493,1498,1503],{"text":1479,"config":1480},"Install",{"href":1481,"dataGaName":1482,"dataGaLocation":1314},"/install/","install",{"text":1484,"config":1485},"Quick start guides",{"href":1486,"dataGaName":1487,"dataGaLocation":1314},"/get-started/","quick setup checklists",{"text":1489,"config":1490},"Learn",{"href":1491,"dataGaLocation":1314,"dataGaName":1492},"https://university.gitlab.com/","learn",{"text":1494,"config":1495},"Product documentation",{"href":1496,"dataGaName":1497,"dataGaLocation":1314},"https://docs.gitlab.com/","product documentation",{"text":1499,"config":1500},"Best practice videos",{"href":1501,"dataGaName":1502,"dataGaLocation":1314},"/getting-started-videos/","best practice videos",{"text":1504,"config":1505},"Integrations",{"href":1506,"dataGaName":1507,"dataGaLocation":1314},"/integrations/","integrations",{"title":1509,"items":1510},"Discover",[1511,1516,1521,1526,1530],{"text":1512,"config":1513},"Customer success stories",{"href":1514,"dataGaName":1515,"dataGaLocation":1314},"/customers/","customer success stories",{"text":1517,"config":1518},"Blog",{"href":1519,"dataGaName":1520,"dataGaLocation":1314},"/blog/","blog",{"text":1522,"config":1523},"Demo Hub",{"href":1524,"dataGaName":1525,"dataGaLocation":1314},"/demo-hub/","demo hub",{"text":1527,"config":1528},"The Source",{"href":1529,"dataGaName":1520,"dataGaLocation":1314},"/the-source/",{"text":1531,"config":1532},"Remote",{"href":1533,"dataGaName":1534,"dataGaLocation":1314},"https://handbook.gitlab.com/handbook/company/culture/all-remote/","remote",{"title":1536,"items":1537},"Connect",[1538,1543,1548,1553,1558,1563],{"text":1539,"config":1540},"GitLab Services",{"href":1541,"dataGaName":1542,"dataGaLocation":1314},"/services/","services",{"text":1544,"config":1545},"Contribute",{"href":1546,"dataGaName":1547,"dataGaLocation":1314},"https://contributors.gitlab.com","contribute",{"text":1549,"config":1550},"Community",{"href":1551,"dataGaName":1552,"dataGaLocation":1314},"/community/","community",{"text":1554,"config":1555},"Forum",{"href":1556,"dataGaName":1557,"dataGaLocation":1314},"https://forum.gitlab.com/","forum",{"text":1559,"config":1560},"Events",{"href":1561,"dataGaName":1562,"dataGaLocation":1314},"/events/","events",{"text":1564,"config":1565},"Partners",{"href":1566,"dataGaName":1567,"dataGaLocation":1314},"/partners/","partners",{"config":1569,"title":1572,"text":1573,"link":1574},{"background":1570,"textColor":1571},"url('https://res.cloudinary.com/about-gitlab-com/image/upload/v1777322348/qpq8yrgn8knii57omj0c.png')","#000","What’s new in GitLab","Stay updated with our latest features and improvements.",{"text":1575,"config":1576},"Read the latest",{"href":1577,"dataGaName":1578,"dataGaLocation":1314},"/whats-new/","whats new",{"text":1580,"config":1581,"menu":1583},"Company",{"dataNavLevelOne":1582},"company",{"type":1365,"columns":1584},[1585],{"items":1586},[1587,1592,1598,1600,1605,1610,1615,1620,1625,1630],{"text":1588,"config":1589},"About",{"href":1590,"dataGaName":1591,"dataGaLocation":1314},"/company/","about",{"text":1593,"config":1594,"footerGa":1597},"Jobs",{"href":1595,"dataGaName":1596,"dataGaLocation":1314},"/jobs/","jobs",{"dataGaName":1596},{"text":1559,"config":1599},{"href":1561,"dataGaName":1562,"dataGaLocation":1314},{"text":1601,"config":1602},"Leadership",{"href":1603,"dataGaName":1604,"dataGaLocation":1314},"/company/team/e-group/","leadership",{"text":1606,"config":1607},"Handbook",{"href":1608,"dataGaName":1609,"dataGaLocation":1314},"https://handbook.gitlab.com/","handbook",{"text":1611,"config":1612},"Investor relations",{"href":1613,"dataGaName":1614,"dataGaLocation":1314},"https://ir.gitlab.com/overview/default.aspx","investor relations",{"text":1616,"config":1617},"Trust Center",{"href":1618,"dataGaName":1619,"dataGaLocation":1314},"/security/","trust center",{"text":1621,"config":1622},"AI Transparency Center",{"href":1623,"dataGaName":1624,"dataGaLocation":1314},"/ai-transparency-center/","ai transparency center",{"text":1626,"config":1627},"Newsletter",{"href":1628,"dataGaName":1629,"dataGaLocation":1314},"/company/contact/#contact-forms","newsletter",{"text":1631,"config":1632},"Press",{"href":1633,"dataGaName":1634,"dataGaLocation":1314},"/press/","press",{"text":1636,"config":1637,"menu":1638},"Contact us",{"dataNavLevelOne":1582},{"type":1365,"columns":1639},[1640],{"items":1641},[1642,1647,1652],{"text":1643,"config":1644},"Talk to sales",{"href":1645,"dataGaName":1646,"dataGaLocation":1314},"/sales/","talk to sales",{"text":1648,"config":1649},"Support portal",{"href":1650,"dataGaName":1651,"dataGaLocation":1314},"https://support.gitlab.com/hc/en-us","support portal",{"text":1653,"config":1654},"Customer portal",{"href":1655,"dataGaName":1656,"dataGaLocation":1314},"https://customers.gitlab.com/customers/sign_in/","customer portal",{"close":1658,"login":1659,"suggestions":1666},"Close",{"text":1660,"link":1661},"To search repositories and projects, login to",{"text":1662,"config":1663},"gitlab.com",{"href":1328,"dataGaName":1664,"dataGaLocation":1665},"search login","search",{"text":1667,"default":1668},"Suggestions",[1669,1671,1675,1677,1681,1685],{"text":1345,"config":1670},{"href":1350,"dataGaName":1345,"dataGaLocation":1665},{"text":1672,"config":1673},"Code Suggestions (AI)",{"href":1674,"dataGaName":1672,"dataGaLocation":1665},"/solutions/code-suggestions/",{"text":1381,"config":1676},{"href":1383,"dataGaName":1381,"dataGaLocation":1665},{"text":1678,"config":1679},"GitLab on AWS",{"href":1680,"dataGaName":1678,"dataGaLocation":1665},"/partners/technology-partners/aws/",{"text":1682,"config":1683},"GitLab on Google Cloud",{"href":1684,"dataGaName":1682,"dataGaLocation":1665},"/partners/technology-partners/google-cloud-platform/",{"text":1686,"config":1687},"Why GitLab?",{"href":1358,"dataGaName":1686,"dataGaLocation":1665},{"freeTrial":1689,"mobileIcon":1694,"desktopIcon":1699,"secondaryButton":1702},{"text":1690,"config":1691},"Start free trial",{"href":1692,"dataGaName":1319,"dataGaLocation":1693},"https://gitlab.com/-/trials/new/","nav",{"altText":1695,"config":1696},"Gitlab Icon",{"src":1697,"dataGaName":1698,"dataGaLocation":1693},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758203874/jypbw1jx72aexsoohd7x.svg","gitlab icon",{"altText":1695,"config":1700},{"src":1701,"dataGaName":1698,"dataGaLocation":1693},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758203875/gs4c8p8opsgvflgkswz9.svg",{"text":1703,"config":1704},"Get Started",{"href":1705,"dataGaName":1706,"dataGaLocation":1693},"https://gitlab.com/-/trial_registrations/new?glm_source=about.gitlab.com/get-started/","get started",{"freeTrial":1708,"mobileIcon":1712,"desktopIcon":1714},{"text":1709,"config":1710},"Learn more about GitLab Duo",{"href":1350,"dataGaName":1711,"dataGaLocation":1693},"gitlab duo",{"altText":1695,"config":1713},{"src":1697,"dataGaName":1698,"dataGaLocation":1693},{"altText":1695,"config":1715},{"src":1701,"dataGaName":1698,"dataGaLocation":1693},{"button":1717,"mobileIcon":1722,"desktopIcon":1724},{"text":1718,"config":1719},"/switch",{"href":1720,"dataGaName":1721,"dataGaLocation":1693},"#contact","switch",{"altText":1695,"config":1723},{"src":1697,"dataGaName":1698,"dataGaLocation":1693},{"altText":1695,"config":1725},{"src":1726,"dataGaName":1698,"dataGaLocation":1693},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1773335277/ohhpiuoxoldryzrnhfrh.png",{"freeTrial":1728,"mobileIcon":1733,"desktopIcon":1735},{"text":1729,"config":1730},"Back to pricing",{"href":1463,"dataGaName":1731,"dataGaLocation":1693,"icon":1732},"back to pricing","GoBack",{"altText":1695,"config":1734},{"src":1697,"dataGaName":1698,"dataGaLocation":1693},{"altText":1695,"config":1736},{"src":1701,"dataGaName":1698,"dataGaLocation":1693},{"title":1738,"titleMobile":1739,"button":1740,"config":1745},"Duo Agent Platform delivers 400% ROI, per new Forrester Consulting study.","400% ROI: Forrester TEI for GitLab Duo",{"text":1356,"config":1741},{"href":1742,"dataGaName":1743,"dataGaLocation":1744},"https://about.gitlab.com/blog/gitlab-duo-agent-platform-delivers-400-percent-roi/","forrester-tei-dap-banner","global-banner",{"layout":1746,"disabled":1293},"release",{"data":1748},{"text":1749,"source":1750,"edit":1756,"contribute":1761,"config":1766,"items":1771,"minimal":1978},"Git is a trademark of Software Freedom Conservancy and our use of 'GitLab' is under license",{"text":1751,"config":1752},"View page source",{"href":1753,"dataGaName":1754,"dataGaLocation":1755},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/","page source","footer",{"text":1757,"config":1758},"Edit this page",{"href":1759,"dataGaName":1760,"dataGaLocation":1755},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/-/blob/main/content/","web ide",{"text":1762,"config":1763},"Please contribute",{"href":1764,"dataGaName":1765,"dataGaLocation":1755},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/-/blob/main/CONTRIBUTING.md/","please contribute",{"twitter":1767,"facebook":1768,"youtube":1769,"linkedin":1770},"https://twitter.com/gitlab","https://www.facebook.com/gitlab","https://www.youtube.com/channel/UCnMGQ8QHMAnVIsI3xJrihhg","https://www.linkedin.com/company/gitlab-com",[1772,1818,1870,1914,1946],{"title":1461,"links":1773,"subMenu":1788},[1774,1778,1783],{"text":1775,"config":1776},"View plans",{"href":1463,"dataGaName":1777,"dataGaLocation":1755},"view plans",{"text":1779,"config":1780},"Why Premium?",{"href":1781,"dataGaName":1782,"dataGaLocation":1755},"/pricing/premium/","why premium",{"text":1784,"config":1785},"Why Ultimate?",{"href":1786,"dataGaName":1787,"dataGaLocation":1755},"/pricing/ultimate/","why ultimate",[1789],{"title":1790,"links":1791},"Contact Us",[1792,1795,1797,1799,1803,1808,1813],{"text":1793,"config":1794},"Contact sales",{"href":1645,"dataGaName":1324,"dataGaLocation":1755},{"text":1648,"config":1796},{"href":1650,"dataGaName":1651,"dataGaLocation":1755},{"text":1653,"config":1798},{"href":1655,"dataGaName":1656,"dataGaLocation":1755},{"text":1800,"config":1801},"Status",{"href":1802,"dataGaName":491,"dataGaLocation":1755},"https://status.gitlab.com/",{"text":1804,"config":1805},"Terms of use",{"href":1806,"dataGaName":1807,"dataGaLocation":1755},"/terms/","terms of use",{"text":1809,"config":1810},"Privacy statement",{"href":1811,"dataGaName":1812,"dataGaLocation":1755},"/privacy/","privacy statement",{"text":1814,"config":1815},"Cookie preferences",{"dataGaName":1816,"dataGaLocation":1755,"id":1817,"isOneTrustButton":817},"cookie preferences","ot-sdk-btn",{"title":1361,"links":1819,"subMenu":1828},[1820,1824],{"text":1821,"config":1822},"DevSecOps platform",{"href":1343,"dataGaName":1823,"dataGaLocation":1755},"devsecops platform",{"text":1825,"config":1826},"AI-Assisted Development",{"href":1350,"dataGaName":1827,"dataGaLocation":1755},"ai-assisted development",[1829],{"title":1830,"links":1831},"Topics",[1832,1837,1842,1846,1851,1855,1860,1865],{"text":1833,"config":1834},"CICD",{"href":1835,"dataGaName":1836,"dataGaLocation":1755},"/topics/ci-cd/","cicd",{"text":1838,"config":1839},"GitOps",{"href":1840,"dataGaName":1841,"dataGaLocation":1755},"/topics/gitops/","gitops",{"text":1304,"config":1843},{"href":1844,"dataGaName":1845,"dataGaLocation":1755},"/topics/devops/","devops",{"text":1847,"config":1848},"Version Control",{"href":1849,"dataGaName":1850,"dataGaLocation":1755},"/topics/version-control/","version control",{"text":1852,"config":1853},"DevSecOps",{"href":1854,"dataGaName":1288,"dataGaLocation":1755},"/topics/devsecops/",{"text":1856,"config":1857},"Cloud Native",{"href":1858,"dataGaName":1859,"dataGaLocation":1755},"/topics/cloud-native/","cloud native",{"text":1861,"config":1862},"AI for Coding",{"href":1863,"dataGaName":1864,"dataGaLocation":1755},"/topics/devops/ai-for-coding/","ai for coding",{"text":1866,"config":1867},"Agentic AI",{"href":1868,"dataGaName":1869,"dataGaLocation":1755},"/topics/agentic-ai/","agentic ai",{"title":1871,"links":1872},"Solutions",[1873,1875,1877,1882,1886,1889,1893,1896,1898,1901,1904,1909],{"text":1405,"config":1874},{"href":1400,"dataGaName":1405,"dataGaLocation":1755},{"text":1394,"config":1876},{"href":1377,"dataGaName":1378,"dataGaLocation":1755},{"text":1878,"config":1879},"Agile development",{"href":1880,"dataGaName":1881,"dataGaLocation":1755},"/solutions/agile-delivery/","agile delivery",{"text":1883,"config":1884},"SCM",{"href":1390,"dataGaName":1885,"dataGaLocation":1755},"source code management",{"text":1833,"config":1887},{"href":1383,"dataGaName":1888,"dataGaLocation":1755},"continuous integration & delivery",{"text":1890,"config":1891},"Value stream management",{"href":1433,"dataGaName":1892,"dataGaLocation":1755},"value stream management",{"text":1838,"config":1894},{"href":1895,"dataGaName":1841,"dataGaLocation":1755},"/solutions/gitops/",{"text":1443,"config":1897},{"href":1446,"dataGaName":1447,"dataGaLocation":1755},{"text":1899,"config":1900},"Small business",{"href":1452,"dataGaName":1453,"dataGaLocation":1755},{"text":1902,"config":1903},"Public sector",{"href":1458,"dataGaName":1459,"dataGaLocation":1755},{"text":1905,"config":1906},"Education",{"href":1907,"dataGaName":1908,"dataGaLocation":1755},"/solutions/education/","education",{"text":1910,"config":1911},"Financial services",{"href":1912,"dataGaName":1913,"dataGaLocation":1755},"/solutions/finance/","financial services",{"title":1466,"links":1915},[1916,1918,1920,1922,1925,1927,1930,1932,1934,1936,1938,1940,1942,1944],{"text":1479,"config":1917},{"href":1481,"dataGaName":1482,"dataGaLocation":1755},{"text":1484,"config":1919},{"href":1486,"dataGaName":1487,"dataGaLocation":1755},{"text":1489,"config":1921},{"href":1491,"dataGaName":1492,"dataGaLocation":1755},{"text":1494,"config":1923},{"href":1496,"dataGaName":1924,"dataGaLocation":1755},"docs",{"text":1517,"config":1926},{"href":1519,"dataGaName":1520,"dataGaLocation":1755},{"text":1928,"config":1929},"What's new",{"href":1577,"dataGaName":1578,"dataGaLocation":1755},{"text":1512,"config":1931},{"href":1514,"dataGaName":1515,"dataGaLocation":1755},{"text":1531,"config":1933},{"href":1533,"dataGaName":1534,"dataGaLocation":1755},{"text":1539,"config":1935},{"href":1541,"dataGaName":1542,"dataGaLocation":1755},{"text":1544,"config":1937},{"href":1546,"dataGaName":1547,"dataGaLocation":1755},{"text":1549,"config":1939},{"href":1551,"dataGaName":1552,"dataGaLocation":1755},{"text":1554,"config":1941},{"href":1556,"dataGaName":1557,"dataGaLocation":1755},{"text":1559,"config":1943},{"href":1561,"dataGaName":1562,"dataGaLocation":1755},{"text":1564,"config":1945},{"href":1566,"dataGaName":1567,"dataGaLocation":1755},{"title":1580,"links":1947},[1948,1950,1952,1954,1956,1958,1962,1967,1969,1971,1973],{"text":1588,"config":1949},{"href":1590,"dataGaName":1582,"dataGaLocation":1755},{"text":1593,"config":1951},{"href":1595,"dataGaName":1596,"dataGaLocation":1755},{"text":1601,"config":1953},{"href":1603,"dataGaName":1604,"dataGaLocation":1755},{"text":1606,"config":1955},{"href":1608,"dataGaName":1609,"dataGaLocation":1755},{"text":1611,"config":1957},{"href":1613,"dataGaName":1614,"dataGaLocation":1755},{"text":1959,"config":1960},"Sustainability",{"href":1961,"dataGaName":1959,"dataGaLocation":1755},"/sustainability/",{"text":1963,"config":1964},"Diversity, inclusion and belonging (DIB)",{"href":1965,"dataGaName":1966,"dataGaLocation":1755},"/diversity-inclusion-belonging/","Diversity, inclusion and belonging",{"text":1616,"config":1968},{"href":1618,"dataGaName":1619,"dataGaLocation":1755},{"text":1626,"config":1970},{"href":1628,"dataGaName":1629,"dataGaLocation":1755},{"text":1631,"config":1972},{"href":1633,"dataGaName":1634,"dataGaLocation":1755},{"text":1974,"config":1975},"Modern Slavery Transparency Statement",{"href":1976,"dataGaName":1977,"dataGaLocation":1755},"https://handbook.gitlab.com/handbook/legal/modern-slavery-act-transparency-statement/","modern slavery transparency statement",{"items":1979},[1980,1983,1986],{"text":1981,"config":1982},"Terms",{"href":1806,"dataGaName":1807,"dataGaLocation":1755},{"text":1984,"config":1985},"Cookies",{"dataGaName":1816,"dataGaLocation":1755,"id":1817,"isOneTrustButton":817},{"text":1987,"config":1988},"Privacy",{"href":1811,"dataGaName":1812,"dataGaLocation":1755},[1990],{"id":1991,"title":7,"body":1292,"config":1992,"content":1994,"description":1292,"extension":1997,"meta":1998,"navigation":817,"path":1999,"seo":2000,"stem":2001,"__hash__":2002},"blogAuthors/en-us/blog/authors/philip-welz.yml",{"template":1993},"BlogAuthor",{"name":7,"config":1995},{"headshot":120,"ctfId":1996},"philxx","yml",{},"/en-us/blog/authors/philip-welz",{},"en-us/blog/authors/philip-welz","Wxv6es_WAIIfY0f_SSeeUWCaQD-o2S8si2saEX2-hOk",[2004,2012,2020],{"title":2005,"description":2006,"heroImage":2007,"category":1288,"date":2008,"authors":2009,"slug":2011,"externalUrl":1292},"Consolidate your GitLab stack with Gitaly on Kubernetes","Discover how to install Gitaly on Kubernetes, which is now generally available.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1756500636/wmey6kqzzuhirk88w2de.png","2026-05-07",[2010],"Olivier Campeau","gitaly-on-kubernetes-generally-available",{"title":2013,"description":2014,"heroImage":2015,"category":1288,"date":2016,"authors":2017,"slug":2019,"externalUrl":1292},"Teaching software development the easy way using GitLab","Learn how University of Washington lecturer Stephen G. Dame uses GitLab for Education to manage student assignments, distribute course materials, and provide inline code feedback at scale.\n","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749659537/Blog/Hero%20Images/display-article-image-0679-1800x945-fy26.png","2026-04-29",[2018],"Rod Burns","teaching-software-development-the-easy-way-using-gitlab",{"title":2021,"description":2022,"heroImage":2023,"category":1288,"date":2024,"authors":2025,"slug":2027,"externalUrl":1292},"AI is reshaping DevSecOps: Attend GitLab Transcend to see what’s next","AI-generated code is 34% of development work. Discover how to balance productivity gains with quality, reliability, and security.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1767982271/e9ogyosmuummq7j65zqg.png","2026-01-08",[2026],"Manav Khurana","ai-is-reshaping-devsecops-attend-gitlab-transcend-to-see-whats-next",{"promotions":2029},[2030,2044,2056,2068],{"id":2031,"categories":2032,"header":2034,"text":2035,"button":2036,"image":2041},"ai-modernization",[2033],"ai","Is AI achieving its promise at scale?","Quiz will take 5 minutes or less",{"text":2037,"config":2038},"Get your AI maturity score",{"href":2039,"dataGaName":2040,"dataGaLocation":1520},"/assessments/ai-modernization-assessment/","modernization assessment",{"config":2042},{"src":2043},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1772138786/qix0m7kwnd8x2fh1zq49.png",{"id":2045,"categories":2046,"header":2048,"text":2035,"button":2049,"image":2053},"devops-modernization",[2047,1288],"product","Are you just managing tools or shipping innovation?",{"text":2050,"config":2051},"Get your DevOps maturity score",{"href":2052,"dataGaName":2040,"dataGaLocation":1520},"/assessments/devops-modernization-assessment/",{"config":2054},{"src":2055},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1772138785/eg818fmakweyuznttgid.png",{"id":2057,"categories":2058,"header":2060,"text":2035,"button":2061,"image":2065},"security-modernization",[2059],"security","Are you trading speed for security?",{"text":2062,"config":2063},"Get your security maturity score",{"href":2064,"dataGaName":2040,"dataGaLocation":1520},"/assessments/security-modernization-assessment/",{"config":2066},{"src":2067},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1772138786/p4pbqd9nnjejg5ds6mdk.png",{"id":2069,"paths":2070,"header":2073,"text":2074,"button":2075,"image":2080},"github-azure-migration",[2071,2072],"migration-from-azure-devops-to-gitlab","integrating-azure-devops-scm-and-gitlab","Is your team ready for GitHub's Azure move?","GitHub is already rebuilding around Azure. Find out what it means for you.",{"text":2076,"config":2077},"See how GitLab compares to GitHub",{"href":2078,"dataGaName":2079,"dataGaLocation":1520},"/compare/gitlab-vs-github/github-azure-migration/","github azure migration",{"config":2081},{"src":2055},{"header":2083,"blurb":2084,"button":2085,"secondaryButton":2090},"Start building faster today","See what your team can do with the intelligent orchestration platform for DevSecOps.\n",{"text":2086,"config":2087},"Get your free trial",{"href":2088,"dataGaName":1319,"dataGaLocation":2089},"https://gitlab.com/-/trial_registrations/new?glm_content=default-saas-trial&glm_source=about.gitlab.com/","feature",{"text":1793,"config":2091},{"href":1645,"dataGaName":1324,"dataGaLocation":2089},1786803762838]