{"id":67,"date":"2025-06-21T00:36:39","date_gmt":"2025-06-20T22:36:39","guid":{"rendered":"https:\/\/holasocnando.com\/?p=67"},"modified":"2026-01-18T00:35:33","modified_gmt":"2026-01-17T22:35:33","slug":"creating-a-ci-cd-environment-part-1","status":"publish","type":"post","link":"https:\/\/holasocnando.com\/en\/creating-a-ci-cd-environment-part-1\/","title":{"rendered":"Creating a CI\/CD Environment (Part 1)"},"content":{"rendered":"<p>I&#8217;m going to create a Docker container infrastructure for CI\/CD. Let\u2019s assume we already have a Docker installation with Portainer.<\/p>\n<h2 data-start=\"239\" data-end=\"294\">Essential Containers for CI\/CD:<\/h2>\n<ul>\n<li data-start=\"296\" data-end=\"316\"><strong data-start=\"303\" data-end=\"316\">GitLab CE<\/strong>\n<ul>\n<li data-start=\"317\" data-end=\"389\">\n<p data-start=\"319\" data-end=\"389\"><strong data-start=\"192\" data-end=\"205\">Function:<\/strong> Code repository + pipeline management.<\/p>\n<\/li>\n<li data-start=\"390\" data-end=\"422\">\n<p data-start=\"392\" data-end=\"422\"><strong data-start=\"392\" data-end=\"402\">Image<\/strong>: <code data-start=\"404\" data-end=\"422\"><a href=\"https:\/\/hub.docker.com\/r\/gitlab\/gitlab-ce\" target=\"_blank\" rel=\"noopener\">gitlab\/gitlab-ce<\/a><\/code><\/p>\n<\/li>\n<li data-start=\"423\" data-end=\"500\">\n<p data-start=\"425\" data-end=\"442\"><strong data-start=\"425\" data-end=\"441\">Ports<\/strong>:<\/p>\n<ul data-start=\"445\" data-end=\"500\">\n<li data-start=\"445\" data-end=\"455\">\n<p data-start=\"447\" data-end=\"455\">80: HTTP (web interface)<\/p>\n<\/li>\n<li data-start=\"458\" data-end=\"470\">\n<p data-start=\"460\" data-end=\"470\">443: HTTPS (web interface)<\/p>\n<\/li>\n<li data-start=\"473\" data-end=\"500\">\n<p data-start=\"475\" data-end=\"500\">22: SSH (clone the repository and commit to the remote)<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li data-start=\"501\" data-end=\"650\">\n<p data-start=\"503\" data-end=\"522\"><strong data-start=\"503\" data-end=\"521\">Considerations<\/strong>:<\/p>\n<ul data-start=\"525\" data-end=\"650\">\n<li data-start=\"558\" data-end=\"650\">Mount volumes for persistent data:\n<ul data-start=\"525\" data-end=\"650\">\n<li data-start=\"558\" data-end=\"650\">\/etc\/gitlab<\/li>\n<li data-start=\"558\" data-end=\"650\">\/var\/opt\/gitlab<\/li>\n<li data-start=\"558\" data-end=\"650\">var\/log\/gitlab<code data-start=\"614\" data-end=\"631\"><\/code><code data-start=\"633\" data-end=\"650\"><\/code><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<li data-start=\"652\" data-end=\"676\"><strong data-start=\"659\" data-end=\"676\">GitLab Runner<\/strong>\n<ul>\n<li data-start=\"677\" data-end=\"749\">\n<p data-start=\"679\" data-end=\"749\"><strong data-start=\"564\" data-end=\"577\">Function:<\/strong> Executes pipeline jobs (build, test, deploy, etc.)<\/p>\n<\/li>\n<li data-start=\"750\" data-end=\"786\">\n<p data-start=\"752\" data-end=\"786\"><strong data-start=\"752\" data-end=\"762\">Image<\/strong>: <code data-start=\"764\" data-end=\"786\"><a href=\"https:\/\/hub.docker.com\/r\/gitlab\/gitlab-runner\" target=\"_blank\" rel=\"noopener\">gitlab\/gitlab-runner<\/a><\/code><\/p>\n<\/li>\n<li data-start=\"787\" data-end=\"927\">\n<p data-start=\"789\" data-end=\"810\"><strong data-start=\"789\" data-end=\"809\">Execution types:<\/strong><\/p>\n<ul data-start=\"813\" data-end=\"927\">\n<li data-start=\"813\" data-end=\"869\">\n<p data-start=\"815\" data-end=\"869\">Docker: Each job runs inside a separate container. (I\u2019ll use this one.)<\/p>\n<\/li>\n<li data-start=\"872\" data-end=\"927\">\n<p data-start=\"874\" data-end=\"927\">Shell: Jobs run directly on the host (or container).<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<h2>Recommended Folder Structure:<\/h2>\n<div class=\"hcb_wrap\">\n<pre class=\"prism line-numbers lang-bash\" data-lang=\"Bash\"><code>\/infra-ci-cd\/\r\n\u2502\r\n\u251c\u2500\u2500 docker-compose.yml\r\n\u251c\u2500\u2500 gitlab\/\r\n\u2502     \u251c\u2500\u2500 config\/\r\n\u2502     \u251c\u2500\u2500 logs\/\r\n\u2502     \u2514\u2500\u2500 data\/\r\n\u2502\r\n\u2514\u2500\u2500 runner\/\r\n\u2514\u2500\u2500 config\/<\/code><\/pre>\n<\/div>\n<h2>Container Creation<\/h2>\n<div class=\"hcb_wrap\">\n<pre class=\"prism line-numbers lang-git\" data-lang=\"Git\"><code>#docker-compose.yml\r\n\r\nservices:\r\n  gitlab:\r\n    image: gitlab\/gitlab-ce:latest\r\n    restart: always\r\n    hostname: 'gitlab.local'\r\n    ports:\r\n      - '880:80'\r\n      - '8443:443'\r\n      - '822:22'\r\n    volumes:\r\n      - '.\/gitlab\/config:\/etc\/gitlab'\r\n      - '.\/gitlab\/logs:\/var\/log\/gitlab'\r\n      - '.\/gitlab\/data:\/var\/opt\/gitlab'\r\n\r\n  gitlab-runner:\r\n    image: gitlab\/gitlab-runner:latest\r\n    restart: always\r\n    volumes:\r\n      - '.\/runner\/config:\/etc\/gitlab-runner'\r\n      - '\/var\/run\/docker.sock:\/var\/run\/docker.sock'<\/code><\/pre>\n<\/div>\n<p>I\u2019ve specified different ports on the local machine mapped to the necessary container ports to avoid conflicts:<\/p>\n<div class=\"hcb_wrap\">\n<pre class=\"prism line-numbers lang-git\" data-lang=\"Git\"><code>ports:\r\n  - '880:80'\r\n  - '8443:443'\r\n  - '822:22'<\/code><\/pre>\n<\/div>\n<p>&nbsp;<\/p>\n<p>Once everything is set up, run:<\/p>\n<div class=\"hcb_wrap\">\n<pre class=\"prism line-numbers lang-bash\" data-lang=\"Bash\"><code>docker compose up -d<\/code><\/pre>\n<\/div>\n<p>This will start the containers, which we can view in Portainer.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/holasocnando.com\/wp-content\/uploads\/2025\/06\/Captura-desde-2025-06-21-00-30-09-1024x227.png\" alt=\"\" width=\"1024\" height=\"227\" class=\"alignnone wp-image-75 size-large\" srcset=\"https:\/\/holasocnando.com\/wp-content\/uploads\/2025\/06\/Captura-desde-2025-06-21-00-30-09-1024x227.png 1024w, https:\/\/holasocnando.com\/wp-content\/uploads\/2025\/06\/Captura-desde-2025-06-21-00-30-09-300x66.png 300w, https:\/\/holasocnando.com\/wp-content\/uploads\/2025\/06\/Captura-desde-2025-06-21-00-30-09-768x170.png 768w, https:\/\/holasocnando.com\/wp-content\/uploads\/2025\/06\/Captura-desde-2025-06-21-00-30-09.png 1436w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/p>\n<h2>Accessing GitLab<\/h2>\n<p>In the <code data-start=\"1230\" data-end=\"1242\">\/etc\/hosts<\/code> file, I configure the domain <code data-start=\"1272\" data-end=\"1286\">gitlab.local<\/code> to access it via the web browser.<\/p>\n<div class=\"hcb_wrap\">\n<pre class=\"prism line-numbers lang-bash\" data-lang=\"Bash\"><code>#\/etc\/hosts\r\n\r\n127.0.0.1 gitlab.local<\/code><\/pre>\n<\/div>\n<p>&nbsp;<\/p>\n<p>To obtain the root password automatically created by GitLab, run:<\/p>\n<div class=\"hcb_wrap\">\n<pre class=\"prism line-numbers lang-bash\" data-lang=\"Bash\"><code>docker exec -it [nom_contenidor_gitlab] grep 'Password:' \/etc\/gitlab\/initial_root_password<\/code><\/pre>\n<\/div>\n<p>You can now access <a data-start=\"1414\" data-end=\"1464\" class=\"\" rel=\"noopener\" target=\"_new\" href=\"http:\/\/gitlab.local:880\">http:\/\/gitlab.local:880<\/a> and log in with the <code data-start=\"1485\" data-end=\"1491\">root<\/code> user and the retrieved password. Next, I create a blank project for the API (I&#8217;ll create a new project for the frontend in next steps):<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-93 size-full\" src=\"https:\/\/holasocnando.com\/wp-content\/uploads\/2025\/06\/Captura-desde-2025-06-22-23-46-55.png\" alt=\"\" width=\"929\" height=\"726\" srcset=\"https:\/\/holasocnando.com\/wp-content\/uploads\/2025\/06\/Captura-desde-2025-06-22-23-46-55.png 929w, https:\/\/holasocnando.com\/wp-content\/uploads\/2025\/06\/Captura-desde-2025-06-22-23-46-55-300x234.png 300w, https:\/\/holasocnando.com\/wp-content\/uploads\/2025\/06\/Captura-desde-2025-06-22-23-46-55-768x600.png 768w\" sizes=\"auto, (max-width: 929px) 100vw, 929px\" \/><\/p>\n<p>&nbsp;<\/p>\n<p>In the next part, I\u2019ll make the first commit to configure the pipelines.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I&#8217;m going to create a Docker container infrastructure for CI\/CD. Let\u2019s assume we already have a Docker installation with Portainer. Essential Containers for CI\/CD: GitLab CE Function: Code repository + pipeline management. Image: gitlab\/gitlab-ce Ports: 80: HTTP (web interface) 443: HTTPS (web interface) 22: SSH (clone the repository and commit to the remote) Considerations: Mount [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":69,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[6],"tags":[],"class_list":["post-67","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-devops"],"_links":{"self":[{"href":"https:\/\/holasocnando.com\/en\/wp-json\/wp\/v2\/posts\/67","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/holasocnando.com\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/holasocnando.com\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/holasocnando.com\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/holasocnando.com\/en\/wp-json\/wp\/v2\/comments?post=67"}],"version-history":[{"count":17,"href":"https:\/\/holasocnando.com\/en\/wp-json\/wp\/v2\/posts\/67\/revisions"}],"predecessor-version":[{"id":98,"href":"https:\/\/holasocnando.com\/en\/wp-json\/wp\/v2\/posts\/67\/revisions\/98"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/holasocnando.com\/en\/wp-json\/wp\/v2\/media\/69"}],"wp:attachment":[{"href":"https:\/\/holasocnando.com\/en\/wp-json\/wp\/v2\/media?parent=67"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/holasocnando.com\/en\/wp-json\/wp\/v2\/categories?post=67"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/holasocnando.com\/en\/wp-json\/wp\/v2\/tags?post=67"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}