{
    "componentChunkName": "component---src-templates-docs-js",
    "path": "/vecka7-ci-cd/just-task-it-deploy-pipeline",
    "result": {"data":{"site":{"siteMetadata":{"title":"Linnéuniversitetet","language":"sv","courseCode":"1DV613"}},"mdx":{"fields":{"id":"b599045d-c45e-52f6-be3c-74b5b2d073f4","title":"JTI - Deploy through a pipeline","slug":"/vecka7-ci-cd/just-task-it-deploy-pipeline"},"body":"var _excluded = [\"components\"];\n\nfunction _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }\n\nfunction _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }\n\nfunction _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }\n\n/* @jsxRuntime classic */\n\n/* @jsx mdx */\nvar _frontmatter = {\n  \"title\": \"JTI - Deploy through a pipeline\",\n  \"metaTitle\": \"1dv613 | vecka 7 | JTI - Deploy through a pipeline\",\n  \"metaDescription\": \"metaDescription\",\n  \"order\": 7\n};\nvar layoutProps = {\n  _frontmatter: _frontmatter\n};\nvar MDXLayout = \"wrapper\";\nreturn function MDXContent(_ref) {\n  var components = _ref.components,\n      props = _objectWithoutProperties(_ref, _excluded);\n\n  return mdx(MDXLayout, _extends({}, layoutProps, props, {\n    components: components,\n    mdxType: \"MDXLayout\"\n  }), mdx(\"h2\", null, \"Deploy trough a pipeline\"), mdx(\"p\", null, mdx(\"span\", {\n    parentName: \"p\",\n    \"className\": \"gatsby-resp-image-wrapper\",\n    \"style\": {\n      \"position\": \"relative\",\n      \"display\": \"block\",\n      \"marginLeft\": \"auto\",\n      \"marginRight\": \"auto\",\n      \"maxWidth\": \"1035px\"\n    }\n  }, \"\\n      \", mdx(\"a\", {\n    parentName: \"span\",\n    \"className\": \"gatsby-resp-image-link\",\n    \"href\": \"/kurser/mjukvaruutvecklingsprojekt/static/1e89dc394088cef4d130cf224d59ce24/8bb81/pipeline.png\",\n    \"style\": {\n      \"display\": \"block\"\n    },\n    \"target\": \"_blank\",\n    \"rel\": \"noopener\"\n  }, \"\\n    \", mdx(\"span\", {\n    parentName: \"a\",\n    \"className\": \"gatsby-resp-image-background-image\",\n    \"style\": {\n      \"paddingBottom\": \"16.988416988416986%\",\n      \"position\": \"relative\",\n      \"bottom\": \"0\",\n      \"left\": \"0\",\n      \"backgroundImage\": \"url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAADCAYAAACTWi8uAAAACXBIWXMAABYlAAAWJQFJUiTwAAAAlklEQVQI10WO2QrDMAwE8/9/WQpJ0zZ2Dl+S7EyJS+nDoGUQyw5L3Lg/R9ziUDNyLjSDd1iZ3YvVb4gIIopkJaTMbRl5TDPeeZxzxJgoRZCiDCFnthgwrZjVLk+DaX8z+Sc5JtS0l6aYSamwxqPnau1LbagYKpWh6kmzE9VLNlQrl3Nx5+UXwhH+C4vx/affq+CHaet8AA+m6RHd9+SnAAAAAElFTkSuQmCC')\",\n      \"backgroundSize\": \"cover\",\n      \"display\": \"block\"\n    }\n  }), \"\\n  \", mdx(\"img\", {\n    parentName: \"a\",\n    \"className\": \"gatsby-resp-image-image\",\n    \"alt\": \"A gitlab pipeline showing an automated integration-test-stage and a manual deploy to production step.\",\n    \"title\": \"A gitlab pipeline showing an automated integration-test-stage and a manual deploy to production step.\",\n    \"src\": \"/kurser/mjukvaruutvecklingsprojekt/static/1e89dc394088cef4d130cf224d59ce24/e3189/pipeline.png\",\n    \"srcSet\": [\"/kurser/mjukvaruutvecklingsprojekt/static/1e89dc394088cef4d130cf224d59ce24/a2ead/pipeline.png 259w\", \"/kurser/mjukvaruutvecklingsprojekt/static/1e89dc394088cef4d130cf224d59ce24/6b9fd/pipeline.png 518w\", \"/kurser/mjukvaruutvecklingsprojekt/static/1e89dc394088cef4d130cf224d59ce24/e3189/pipeline.png 1035w\", \"/kurser/mjukvaruutvecklingsprojekt/static/1e89dc394088cef4d130cf224d59ce24/44d59/pipeline.png 1553w\", \"/kurser/mjukvaruutvecklingsprojekt/static/1e89dc394088cef4d130cf224d59ce24/8bb81/pipeline.png 1602w\"],\n    \"sizes\": \"(max-width: 1035px) 100vw, 1035px\",\n    \"style\": {\n      \"width\": \"100%\",\n      \"height\": \"100%\",\n      \"margin\": \"0\",\n      \"verticalAlign\": \"middle\",\n      \"position\": \"absolute\",\n      \"top\": \"0\",\n      \"left\": \"0\"\n    },\n    \"loading\": \"lazy\",\n    \"decoding\": \"async\"\n  }), \"\\n  \"), \"\\n    \")), mdx(\"p\", null, \"When everything works, you want to be able to deploy your code when it is pushed to GitLab. There are many different branching strategies to choose from, and you should probably have the main branch protected so that you always merge it through a Merge Request that can be audited and approved before the code is pushed to production. However, you will start by just making sure that new commits to main will be \", mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"automatically deployed\"), \" to the staging server, and \", mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"manually deployed\"), \" to the production server.\"), mdx(\"h3\", null, \"1 The .gitlab-ci.yml file\"), mdx(\"p\", null, \"To create a pipeline on GitLab, simply create a file named \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \".gitlab-ci.yml\"), \" and place it in the root of your project. (Doing this in the web UI of GitLab is pretty neat.)\"), mdx(\"p\", null, \"Create two stages named \\\"integration-test\\\" (staging) and \\\"deploy\\\" (production). Start with the staging stage first since the production stage is more or less a copy of staging.\"), mdx(\"p\", null, \"Some tips on the way:\"), mdx(\"ul\", null, mdx(\"li\", {\n    parentName: \"ul\"\n  }, \"Setting the \\\"environment\\\" to \\\"staging\\\" and providing a URL will make testing even easier.\"), mdx(\"li\", {\n    parentName: \"ul\"\n  }, \"You need to make sure that the GitLab runner executing the pipeline has access to your private SSH key. GitLab has good information on how to do this.\"), mdx(\"li\", {\n    parentName: \"ul\"\n  }, \"Pay attention to \\\"Verifying the SSH host keys\\\" in the documentation at GitLab. Your runner must trust your newly created servers. (see environment variables)\"), mdx(\"li\", {\n    parentName: \"ul\"\n  }, \"If you created the pipeline from a template, you can lower the sleeps that simulate testing and linting.\")), mdx(\"p\", null, mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://gitlab.lnu.se/1dv613/content/example-dockerized-web-application/-/blob/main/.gitlab-ci.yml?ref_type=heads\"\n  }, \"Example project - .gitlab-ci.yml\")), mdx(\"h3\", null, \"Pipeline environment variables\"), mdx(\"p\", null, \"You need to set some environment variables on your GitLab project. (Settings -> Ci/CD -> Variables)\"), mdx(\"ul\", null, mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"PRODUCTION_HOST\"), \": The IP-address of the production server.\"), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"SSH_PRIVATE_KEY\"), \": The private key used to connection to the servers.\"), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"SESSION_SECRET\"), \": Used by NODE and gets built into the container.\"), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"DOCKER_PORT\"), \": On which port to start Docker. (in our set up server is mapped against 80)\")), mdx(\"p\", null, mdx(\"span\", {\n    parentName: \"p\",\n    \"className\": \"gatsby-resp-image-wrapper\",\n    \"style\": {\n      \"position\": \"relative\",\n      \"display\": \"block\",\n      \"marginLeft\": \"auto\",\n      \"marginRight\": \"auto\",\n      \"maxWidth\": \"1035px\"\n    }\n  }, \"\\n      \", mdx(\"a\", {\n    parentName: \"span\",\n    \"className\": \"gatsby-resp-image-link\",\n    \"href\": \"/kurser/mjukvaruutvecklingsprojekt/static/fbaac09ca74cc3f37ffc8e43faaa14fb/f291a/variables.png\",\n    \"style\": {\n      \"display\": \"block\"\n    },\n    \"target\": \"_blank\",\n    \"rel\": \"noopener\"\n  }, \"\\n    \", mdx(\"span\", {\n    parentName: \"a\",\n    \"className\": \"gatsby-resp-image-background-image\",\n    \"style\": {\n      \"paddingBottom\": \"35.907335907335906%\",\n      \"position\": \"relative\",\n      \"bottom\": \"0\",\n      \"left\": \"0\",\n      \"backgroundImage\": \"url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAHCAYAAAAIy204AAAACXBIWXMAABYlAAAWJQFJUiTwAAABDklEQVQoz2VS2UoEMRDM/3+R4KMvIj4LIqLusiszs3Pk7NwlyZgZdw00oSvV1dVNmJQKfT9AKY2UMlJMa6T1JrJ7njJCiJXrvYcxhGXhNe+7Ad55MMEVppFDCgOtCN7Fq5gnDqPtlpNx+D73taZhzgYM/QRLFmzkhI8zhxK6CgafdkEfYclXkb944bUmBS+CyKiHjYvG52nCMov/gi5CSYJWu0NrQ3VdJmtYDBlPj884fB3BLrPG2+ECvojayd8INjetUeGU5lLojYME3N0/4OX1HWwRhFO3EspotzssYut4u6DkGkqaqx06l5EzwGZhcegEjKb6EEKqblpYcnWP8Rcve1XKbK5Xfqz15Qf8AKy4H2cgAdbhAAAAAElFTkSuQmCC')\",\n      \"backgroundSize\": \"cover\",\n      \"display\": \"block\"\n    }\n  }), \"\\n  \", mdx(\"img\", {\n    parentName: \"a\",\n    \"className\": \"gatsby-resp-image-image\",\n    \"alt\": \"Image showing the variable names listed above\",\n    \"title\": \"Image showing the variable names listed above\",\n    \"src\": \"/kurser/mjukvaruutvecklingsprojekt/static/fbaac09ca74cc3f37ffc8e43faaa14fb/e3189/variables.png\",\n    \"srcSet\": [\"/kurser/mjukvaruutvecklingsprojekt/static/fbaac09ca74cc3f37ffc8e43faaa14fb/a2ead/variables.png 259w\", \"/kurser/mjukvaruutvecklingsprojekt/static/fbaac09ca74cc3f37ffc8e43faaa14fb/6b9fd/variables.png 518w\", \"/kurser/mjukvaruutvecklingsprojekt/static/fbaac09ca74cc3f37ffc8e43faaa14fb/e3189/variables.png 1035w\", \"/kurser/mjukvaruutvecklingsprojekt/static/fbaac09ca74cc3f37ffc8e43faaa14fb/44d59/variables.png 1553w\", \"/kurser/mjukvaruutvecklingsprojekt/static/fbaac09ca74cc3f37ffc8e43faaa14fb/a6d66/variables.png 2070w\", \"/kurser/mjukvaruutvecklingsprojekt/static/fbaac09ca74cc3f37ffc8e43faaa14fb/f291a/variables.png 2258w\"],\n    \"sizes\": \"(max-width: 1035px) 100vw, 1035px\",\n    \"style\": {\n      \"width\": \"100%\",\n      \"height\": \"100%\",\n      \"margin\": \"0\",\n      \"verticalAlign\": \"middle\",\n      \"position\": \"absolute\",\n      \"top\": \"0\",\n      \"left\": \"0\"\n    },\n    \"loading\": \"lazy\",\n    \"decoding\": \"async\"\n  }), \"\\n  \"), \"\\n    \")), mdx(\"h3\", null, \"2 Validate your pipeline\"), mdx(\"p\", null, \"Start by validating the pipeline by entering the \\\"CI/CD editor\\\" (CI/CD->Editor) and clicking \\\"validate\\\". Here you can show a visualization of the pipeline and a merged version of your pipeline if you are importing parts of the pipeline from other places.\"), mdx(\"p\", null, \"To run the pipeline you can either:\"), mdx(\"ul\", null, mdx(\"li\", {\n    parentName: \"ul\"\n  }, \"Push a new commit to the project.\"), mdx(\"li\", {\n    parentName: \"ul\"\n  }, \"Click \\\"Run Pipeline\\\" in CI/CD->Pipelines.\")), mdx(\"p\", null, \"You can always enter a stage in the pipeline and look at the command-line output to troubleshoot.\"), mdx(\"p\", null, \"Make a notable change in the CSS or a view file and wait for the pipeline to finish executing. Click Deployments->Environments to get the link to the application. Visit and confirm.\"), mdx(\"h3\", null, \"3 Trigger pipeline\"), mdx(\"p\", null, \"Every time you make a change in your repo the pipeline will try again. It is also possible to manually retrigger the jobs in Gitlab.\"), mdx(\"p\", null, \"Once everything worked you should be able to open \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"PRODUCTION_HOST\"), \" in the browser and see the JTI application.\"), mdx(\"p\", null, \"You now have a CI/CD pipeline for your application. You can develop the application locally, and new versions are easily deployable.\"), mdx(\"h3\", null, \"4 Troubleshooting\"), mdx(\"p\", null, \"If your pipeline fails or your application doesn't deploy correctly, here are some common troubleshooting steps:\"), mdx(\"ul\", null, mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"p\", {\n    parentName: \"li\"\n  }, mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"Examine the GitLab Pipeline Output:\"), \" Click on the failed stage or job in the GitLab UI to see the detailed logs. This output often contains error messages that can pinpoint the issue. Look for specific error codes or messages related to SSH, Docker, or your application.\")), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"p\", {\n    parentName: \"li\"\n  }, mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"SSH Connection Issues:\")), mdx(\"ul\", {\n    parentName: \"li\"\n  }, mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"strong\", {\n    parentName: \"li\"\n  }, \"Verify \", mdx(\"inlineCode\", {\n    parentName: \"strong\"\n  }, \"SSH_PRIVATE_KEY\"), \":\"), \" Ensure the \", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"SSH_PRIVATE_KEY\"), \" variable in GitLab is correctly set and matches the private key on your GitLab runner. Double-check for any extra spaces or line breaks.\"), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"strong\", {\n    parentName: \"li\"\n  }, \"Verify Host Key:\"), \" Make sure the host key for your production server has been correctly added to the \", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"known_hosts\"), \" file. The \", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \".before_script_ssh_setup\"), \" should handle this, but verify the logs for any errors related to \", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"ssh-keyscan\"), \". You might need to manually SSH into the server from the runner (if possible for debugging) to add the key.\"), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"strong\", {\n    parentName: \"li\"\n  }, \"Firewall Rules:\"), \" Check if there are any firewall rules on your production server that might be blocking incoming SSH connections from the GitLab runner. Ensure port 22 is open.\"))), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"p\", {\n    parentName: \"li\"\n  }, mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"Docker Issues:\")), mdx(\"ul\", {\n    parentName: \"li\"\n  }, mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"strong\", {\n    parentName: \"li\"\n  }, \"Docker Installation:\"), \" Confirm that Docker and Docker Compose are correctly installed and running on your production server (as set up by the \", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"cloud-init\"), \" script). You can SSH into the server and run \", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"sudo systemctl status docker\"), \" and \", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"docker compose version\"), \".\"), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"strong\", {\n    parentName: \"li\"\n  }, \"Docker Compose Errors:\"), \" Review the output of the \", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"docker compose up --build -d\"), \" command in the pipeline logs. Look for errors related to building the Docker image, pulling images, or starting containers.\"), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"strong\", {\n    parentName: \"li\"\n  }, \"Container Logs:\"), \" If the containers start successfully but your application doesn't work, SSH into the production server and use \", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"docker ps\"), \" to see the running containers. Then, use \", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"docker logs <container_id>\"), \" to view the logs of your application container for any application-level errors.\"), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"strong\", {\n    parentName: \"li\"\n  }, \"Port Mapping:\"), \" Ensure that the \", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"DOCKER_PORT\"), \" environment variable is correctly configured and that the port mapping in your \", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"docker-compose.yaml\"), \" file is as expected (e.g., mapping the container port to port 80 on the host).\"))), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"p\", {\n    parentName: \"li\"\n  }, mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"Environment Variable Issues:\")), mdx(\"ul\", {\n    parentName: \"li\"\n  }, mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"strong\", {\n    parentName: \"li\"\n  }, \"GitLab Variables:\"), \" Double-check that all the required environment variables (\", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"PRODUCTION_HOST\"), \", \", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"SSH_PRIVATE_KEY\"), \", \", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"SESSION_SECRET\"), \", \", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"DOCKER_PORT\"), \") are correctly defined in GitLab's CI/CD settings.\"), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"strong\", {\n    parentName: \"li\"\n  }, \"Application Access:\"), \" Ensure that your application within the Docker container is correctly accessing these environment variables.\"))), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"p\", {\n    parentName: \"li\"\n  }, mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"Server Resource Issues:\"), \" Although less common for basic deployments, check if your production server has sufficient resources (CPU, memory) to run the Docker containers.\"))), mdx(\"p\", null, \"By systematically checking these areas based on the error messages in your pipeline logs, you should be able to diagnose and resolve most deployment issues. Remember to make small changes and re-run the pipeline after each potential fix to isolate the problem.\"));\n}\n;\nMDXContent.isMDXComponent = true;","tableOfContents":{"items":[{"url":"#deploy-trough-a-pipeline","title":"Deploy trough a pipeline","items":[{"url":"#1-the-gitlab-ciyml-file","title":"1 The .gitlab-ci.yml file"},{"url":"#pipeline-environment-variables","title":"Pipeline environment variables"},{"url":"#2-validate-your-pipeline","title":"2 Validate your pipeline"},{"url":"#3-trigger-pipeline","title":"3 Trigger pipeline"},{"url":"#4-troubleshooting","title":"4 Troubleshooting"}]}]},"parent":{"relativePath":"vecka7-ci-cd/just-task-it-deploy-pipeline.md"},"frontmatter":{"metaTitle":"1dv613 | vecka 7 | JTI - Deploy through a pipeline","metaDescription":"metaDescription","fullWidth":null}},"allMdx":{"edges":[{"node":{"fields":{"slug":"/","title":"🎉 Välkommen till Mjukvaruutvecklingsprojekt (1DV613)"}}},{"node":{"fields":{"slug":"/video-loggar","title":"Videologgar"}}},{"node":{"fields":{"slug":"/studieguiden","title":"Studieguiden"}}},{"node":{"fields":{"slug":"/studieguiden/kommunikationsstrategi","title":"Kommunikationsstrategi"}}},{"node":{"fields":{"slug":"/studieguiden/kursledning","title":"Kursledning"}}},{"node":{"fields":{"slug":"/studieguiden/kursplan","title":"Kursplan och betyg"}}},{"node":{"fields":{"slug":"/studieguiden/litteratur","title":"Kurslitteratur"}}},{"node":{"fields":{"slug":"/studieguiden/schema","title":"Schema och deadlines"}}},{"node":{"fields":{"slug":"/studieguiden/studieanvisningar","title":"Studieanvisningar"}}},{"node":{"fields":{"slug":"/studieguiden/utvarderingar","title":"Kursvärderingar"}}},{"node":{"fields":{"slug":"/vecka1-2-planering-vision/dokumentation","title":"Dokumentation"}}},{"node":{"fields":{"slug":"/vecka1-2-planering-vision","title":"Vecka 1/2 - Planering och vision"}}},{"node":{"fields":{"slug":"/vecka1-2-planering-vision/todo","title":"📅 Att göra-lista"}}},{"node":{"fields":{"slug":"/vecka1-2-planering-vision/vision","title":"Projektvision"}}},{"node":{"fields":{"slug":"/vecka10-etik","title":"Vecka 10 - Etik & överlämning"}}},{"node":{"fields":{"slug":"/vecka10-etik/todo","title":"Att göra lista"}}},{"node":{"fields":{"slug":"/vecka3-krav-test/arbeta-i-projekt","title":"Att arbeta i projekt"}}},{"node":{"fields":{"slug":"/vecka3-krav-test","title":"Vecka 3 - Krav och testning"}}},{"node":{"fields":{"slug":"/vecka3-krav-test/testning","title":"Testning"}}},{"node":{"fields":{"slug":"/vecka3-krav-test/todo","title":"Att göra lista"}}},{"node":{"fields":{"slug":"/vecka3-krav-test/vecka3-krav-test","title":"Kravhantering"}}},{"node":{"fields":{"slug":"/vecka4-implementation/arkitektur","title":"Introduktion till mjukvaruarkitektur"}}},{"node":{"fields":{"slug":"/vecka4-implementation/docker-teori","title":"Introduktion till containers"}}},{"node":{"fields":{"slug":"/vecka4-implementation","title":"Vecka 4 - Implementation"}}},{"node":{"fields":{"slug":"/vecka4-implementation/just-task-it-docker","title":"Introduktion till Docker"}}},{"node":{"fields":{"slug":"/vecka4-implementation/todo","title":"Att göra lista"}}},{"node":{"fields":{"slug":"/vecka5-versionshantering","title":"Vecka 5 - Versionshantering"}}},{"node":{"fields":{"slug":"/vecka5-versionshantering/jobba-med-git","title":"Jobba med Git"}}},{"node":{"fields":{"slug":"/vecka5-versionshantering/todo","title":"Att göra lista"}}},{"node":{"fields":{"slug":"/vecka5-versionshantering/versionshantering","title":"Versionshantering"}}},{"node":{"fields":{"slug":"/vecka6-drift/docker-compose-teori","title":"Introduktion till Docker compose"}}},{"node":{"fields":{"slug":"/vecka6-drift","title":"Vecka 6 - Driftsättning"}}},{"node":{"fields":{"slug":"/vecka6-drift/just-task-it-docker-compose","title":"JTI - Docker Compose"}}},{"node":{"fields":{"slug":"/vecka6-drift/just-task-it-production","title":"JTI - Production"}}},{"node":{"fields":{"slug":"/vecka6-drift/todo","title":"Att göra lista"}}},{"node":{"fields":{"slug":"/vecka7-ci-cd/ci-cd","title":"CI/CD"}}},{"node":{"fields":{"slug":"/vecka7-ci-cd","title":"Vecka 7 - CI/CD"}}},{"node":{"fields":{"slug":"/vecka7-ci-cd/just-task-it-deploy-pipeline","title":"JTI - Deploy through a pipeline"}}},{"node":{"fields":{"slug":"/vecka7-ci-cd/todo","title":"Att göra lista"}}},{"node":{"fields":{"slug":"/vecka8-automatiska-test/automatiska-tester","title":"Automatiserad testning"}}},{"node":{"fields":{"slug":"/vecka8-automatiska-test","title":"Vecka 8 - Automatiserad testning"}}},{"node":{"fields":{"slug":"/vecka8-automatiska-test/todo","title":"Att göra lista"}}},{"node":{"fields":{"slug":"/vecka1-2-planering-vision/extern-updragsgivare","title":"Extern uppdragsgivare"}}},{"node":{"fields":{"slug":"/vecka9-leverans","title":"Vecka 9 - Slutleverans"}}},{"node":{"fields":{"slug":"/vecka1-2-planering-vision/extern-updragsgivare/extern-uppdragsgivare-samverkan","title":"Samverkansinformation: studentprojekt med extern uppdragsgivare"}}},{"node":{"fields":{"slug":"/vecka9-leverans/todo","title":"Att göra lista"}}},{"node":{"fields":{"slug":"/vecka1-2-planering-vision/extern-updragsgivare/vagledning","title":"Vägledning för arbete med extern uppdragsgivare"}}}]}},"pageContext":{"id":"b599045d-c45e-52f6-be3c-74b5b2d073f4"}},
    "staticQueryHashes": ["253607798","3706406642","710574383"]}