{"id":21064,"date":"2021-09-11T14:22:25","date_gmt":"2021-09-11T12:22:25","guid":{"rendered":"https:\/\/blog.mi.hdm-stuttgart.de\/?p=21064"},"modified":"2023-06-18T17:58:20","modified_gmt":"2023-06-18T15:58:20","slug":"how-do-you-get-a-web-application-into-the-cloud","status":"publish","type":"post","link":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2021\/09\/11\/how-do-you-get-a-web-application-into-the-cloud\/","title":{"rendered":"How do you get a web application into the cloud?"},"content":{"rendered":"\n<p><strong>by Dominik Ratzel (dr079) and Alischa Fritzsche (af094)<\/strong><\/p>\n\n\n<p>For the lecture &#8220;Software Development for Cloud Computing&#8221;, we set ourselves the goal of exploring new things and gaining experience. We focused on one topic: &#8220;How do you get a web application into the cloud?&#8221;. In doing so, we took a closer look at Continuous Integration \/ Continuous Delivery, Infrastructure as a Code, and Secure Sockets Layer. In the following, we would like to share our experiences.<\/p>\n\n\n<h2 class=\"wp-block-heading\">Overview of the content of this blog post<\/h2>\n\n\n\n<ul class=\"wp-block-list\"><li>Comparison GitLab and GitHub&nbsp;<ul><li>CI\/CD in GitLab&nbsp;<ul><li><em>Problem: <\/em>Where are the CI\/CD settings in the HdM Gitlab?&nbsp;<\/li><li><em>Problem: <\/em>Solve Docker in Docker by creating a runner&nbsp;<\/li><\/ul><\/li><li>CI\/CD in GitHub&nbsp;<\/li><\/ul><\/li><li>Set up SSL for the web application&nbsp;<ul><li><em>Problem<\/em>: A lot of manual effort&nbsp;<ul><li>Watchtower&nbsp;<\/li><li>Terraform&nbsp;<\/li><\/ul><\/li><\/ul><\/li><li>Testing&nbsp;<ul><li>Create a test environment&nbsp;<\/li><li>Automated Selenium frontend testing in GitHub&nbsp;<\/li><\/ul><\/li><li>Docker Compose&nbsp;<\/li><li><em>Problem<\/em>: How to build amd64 images locally with an arm64 processor?&nbsp;<\/li><\/ul>\n\n\n<h2>Continuous Integration \/ Continuous Delivery<\/h2>\n<p>At the very beginning, we asked ourselves which platform was best suited for our approach. We limited ourselves to the best-known platforms so that the comparison would not be too complex: GitHub and GitLab. <br>Another point we wanted to try was setting up a runner. For this purpose, we set up a simple pipeline in both GitLab and GitHub to update Docker images on Docker Hub.<\/p>\n<h3>GitLab vs. GitHub<\/h3>\n<p>GitHub is considered the original cloud-based Git platform. The platform focuses primarily on the community. Comparatively, it is also the largest (as of January 2020: 40 million users). GitLab is the self-hosted open-source alternative to GitHub. During our research, we noticed the following differences concerning our project.<\/p>\n\n\n<figure class=\"wp-block-table\"><table><tbody><tr><td><\/td><td>GitLab&nbsp;<\/td><td>GitHub&nbsp;<\/td><\/tr><tr><td>Free private and public repositories&nbsp;<\/td><td style=\"font-weight: 100;\">\u2713&nbsp;<\/td><td style=\"font-weight: 100;\">\u2713&nbsp;(since&nbsp;Jan. 2019)<\/td><\/tr><tr><td>Enterprise&nbsp;versions&nbsp;<\/td><td style=\"font-weight: 100;\">\u2713&nbsp;<\/td><td style=\"font-weight: 100;\">\u2713&nbsp;<\/td><\/tr><tr><td>Self-hosted&nbsp;version&nbsp;<\/td><td style=\"font-weight: 100;\">\u2713&nbsp;<\/td><td style=\"font-weight: 100;\">\u25cb (only with paid Enterprise plan)&nbsp;<\/td><\/tr><tr><td>CI\/CD with shared or personal runners&nbsp;<\/td><td style=\"font-weight: 100;\">\u2713&nbsp;<\/td><td style=\"font-weight: 100;\">\u25cb&nbsp;(with&nbsp;third-party&nbsp;apps)&nbsp;<\/td><\/tr><tr><td>Wiki&nbsp;<\/td><td style=\"font-weight: 100;\">\u2713&nbsp;<\/td><td style=\"font-weight: 100;\">\u2713&nbsp;<\/td><\/tr><tr><td>Preview&nbsp;code&nbsp;changes&nbsp;<\/td><td style=\"font-weight: 100;\">\u2713&nbsp;<\/td><td style=\"font-weight: 100;\">\u2713&nbsp;<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n<p>Especially the point that it is only possible in GitLab to use self-hosted runners for the CI\/CD pipeline caught our attention. From our point of view, this is a plus for GitLab in terms of data protection. The fact that GitLab can be self-hosted is an advantage but not necessary for our project. Nevertheless, it is worth mentioning, which is why we have included the point in our list. In all other aspects, GitLab and GitHub are very similar.<\/p>\n<h4>CI\/CD &#8211; GitLab vs. GitHub<\/h4>\n<p><strong>GitHub:<\/strong> provides the user so-called GitHub Actions. This way, the user does not have to set up, configure or host his runner. <br>+ very easy to use <br>+ free of charge <br>&#8211; Critical from a data protection perspective, as the code is executed\/read &#8220;somewhere&#8221;<\/p>\n<p><strong>GitLab<\/strong>: To use the CI\/CD, a custom runner must be configured, hosted, and integrated into the code repository. <br>+ code stays on own runner (e.g., passwords and source code are safe) <br>+ the runner can be configured according to one&#8217;s wishes <br>&#8211; complex to set up and configure <br>&#8211; Runner could cost money depending on the platform (e.g., AWS)<\/p>\n<p><em>Additional information:<\/em> HdM offers students so-called shared runners. However, Docker-in-Docker is not possible with these runners for security reasons. In the following, we will explain how we configured our GitLab runners to allow Docker-in-Docker. Another insight was that the Docker_Host variable must not be specified in the pipeline, otherwise the Docker socket will not be found, and the pipeline will fail.<\/p>\n\n\n<figure class=\"wp-block-image size-full is-resized\"><a href=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/CICD.png\"><img loading=\"lazy\" decoding=\"async\" data-attachment-id=\"21073\" data-permalink=\"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2021\/09\/11\/how-do-you-get-a-web-application-into-the-cloud\/cicd\/\" data-orig-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/CICD.png\" data-orig-size=\"840,160\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"CICD\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/CICD.png\" src=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/CICD.png\" alt=\"\" class=\"wp-image-21073\" width=\"593\" height=\"113\" srcset=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/CICD.png 840w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/CICD-300x57.png 300w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/CICD-768x146.png 768w\" sizes=\"auto, (max-width: 593px) 100vw, 593px\" \/><\/a><\/figure>\n\n\n<h3><span class=\"TextRun SCXW187677063 BCX0\" lang=\"EN-US\" xml:lang=\"EN-US\" data-contrast=\"none\"><span class=\"NormalTextRun SCXW187677063 BCX0\" data-ccp-parastyle=\"heading 2\">CI\/CD in GitLab<\/span><\/span><span class=\"EOP SCXW187677063 BCX0\" data-ccp-props=\"{&quot;335559738&quot;:40}\">&nbsp;<\/span><\/h3>\n<h4>Where are the CI\/CD settings in the HdM GitLab?<\/h4>\n<p><span data-preserver-spaces=\"true\">We are probably not the first to notice that the CI\/CD is missing in the MI GitLab navigation. The &#8220;advanced features&#8221; have been disabled to avoid &#8220;overwhelming&#8221; students. However, they can be easily activated via the GitLab settings (Settings &gt; General &gt; Visibility, project features, permissions) (<\/span><a class=\"editor-rtfLink\" href=\"https:\/\/docs.gitlab.com\/ee\/ci\/enable_or_disable_ci.html\" target=\"_blank\" rel=\"noopener\"><span data-preserver-spaces=\"true\">https:\/\/docs.gitlab.com\/ee\/ci\/enable_or_disable_ci.html<\/span><\/a><span data-preserver-spaces=\"true\">).&nbsp;<\/span><\/p>\n<h4>Write the .gitlab-ci.yml file<\/h4>\n<p><span data-preserver-spaces=\"true\">The next step is to write an individual <span style=\"color: #808080;\"><em>.gitlab-ci.yml<\/em><\/span> file (<\/span><a class=\"editor-rtfLink\" href=\"https:\/\/docs.gitlab.com\/ee\/ci\/quick_start\/index.html\" target=\"_blank\" rel=\"noopener\"><span data-preserver-spaces=\"true\">https:\/\/docs.gitlab.com\/ee\/ci\/quick_start\/index.html<\/span><\/a><span data-preserver-spaces=\"true\">).&nbsp;&nbsp;<br><\/span><span data-preserver-spaces=\"true\">The script builds a Docker container and pushes it to Docker Hub. The <em><span style=\"color: #808080;\">DOCKER_USERNAME<\/span><\/em> and <em><span style=\"color: #808080;\">DOCKER_PASSWORD<\/span><\/em> are stored as Variables in GitLab (Settings &gt; CI\/CD &gt; Variables).&nbsp;<br><\/span><span data-preserver-spaces=\"true\"><em>Tip<\/em>: If you want to keep the images private but do not want to pay for the second private repository on Docker Hub (5$\/month), you can create a private repo and push the images separated by tag (in our case, &#8220;frontend&#8221; and &#8220;backend&#8221;).&nbsp;<\/span><\/p>\n\n\n<div class=\"wp-block-jetpack-markdown\"><pre style=\"line-height: 1;font-size: 10px;\"><code class=\"language-yaml\" data-line=\"\">stages:\n  - docker\n\nbuild-push-image:\n  stage: docker\n  image: docker:stable\n  tags:\n    - gitlab-runner\n  cache: {}\n  services:\n    - docker:18.09-dind\n  variables:\n    DOCKER_DRIVER: overlay2\n    DOCKER_TLS_CERTDIR: &quot;&quot;\n    # This variable DOCKER_HOST should never be set, because otherwise the default address of the Docker host will be\n    # overwritten and the runner will not be able to access the socket and the pipeline will fail!\n    # DOCKER_HOST: tcp:\/\/localhost:2375\/\n  before_script: # Install docker-compose\n    - apk add --update --no-cache curl py-pip docker-compose\n  script:\n    - echo $DOCKER_PASSWORD | docker login --username $DOCKER_USERNAME --password-stdin\n    - docker-compose build\n    - docker-compose push\n  only:\n    - master\n\n<\/code><\/pre>\n<\/div>\n\n\n<h4>Configuring Gitlab<\/h4>\n<p>Next, we asked ourselves how we could restrict merges into the master. The goal was only to allow a branch to be added to the master if the pipeline was successful. This setting can be found in Settings &gt; General &gt; Merge requests &gt; Merge checks the item &#8220;Pipelines must succeed&#8221;.<\/p>\n<h4>Setting up and configuring GitLab Runner<\/h4>\n<p>For this, we have written a <em><span style=\"color: #808080;\">runnerSetup.sh<\/span><\/em>.<\/p>\n\n\n<div class=\"wp-block-jetpack-markdown\"><pre style=\"line-height: 1;font-size: 10px;\"><code class=\"language-bash\" data-line=\"\">#!\/bin\/bash\n\n# Download the binary for your system\nsudo curl -L --output \/usr\/local\/bin\/gitlab-runner https:\/\/gitlab-runner-downloads.s3.amazonaws.com\/latest\/binaries\/gitlab-runner-linux-amd64\n\n# Give it permission be executed\nsudo chmod +x \/usr\/local\/bin\/gitlab-runner\n\n# Create a GitLab CI user\nsudo useradd --comment &#039;GitLab Runner&#039; --create-home gitlab-runner --shell \/bin\/bash\n\n# Install and run as service\nsudo gitlab-runner install --user=gitlab-runner --working-directory=\/home\/gitlab-runner\nsudo gitlab-runner start\nsudo gitlab-runner status\n\n# Command to register the runner\nsudo gitlab-runner register --non-interactive --url https:\/\/gitlab.mi.hdm-stuttgart.de\/ \\\n --registration-token asdfX6fZFdaPL5Ckna4qad3ojr --tag-list gitlab-runner --description gitlab-runner \\\n --executor docker --docker-image docker:stable \\\n --docker-volumes \/var\/run\/docker.sock:\/var\/run\/docker.sock \\\n --docker-privileged\n\n# Install Docker and give the GitLab runner permissions so that it can access the Docker socket.\necho &quot;Installing Docker&quot;\ncurl -fsSL https:\/\/download.docker.com\/linux\/ubuntu\/gpg | sudo apt-key add -\nsudo add-apt-repository &quot;deb [arch=amd64] https:\/\/download.docker.com\/linux\/ubuntu $(lsb_release -cs) stable&quot;\nsudo apt-get update\nsudo apt-get install -y docker-ce\n\nsudo usermod -aG docker gitlab-runner\n\n# Restart Docker and GitLab Runner Service\nsudo systemctl restart gitlab-runner\nsudo systemctl restart docker.service\n\n<\/code><\/pre>\n<\/div>\n\n\n<p>During the step &#8220;<span style=\"color: #808080;\"><em># Command to register the runner<\/em><\/span>&#8221; we fixed the problem we had with the HdM runners. &#8220;<span style=\"color: #808080;\"><em>&#8211;docker-volumes\/var\/run\/docker.sock:\/var\/run\/docker.sock<\/em><\/span>&#8221; gives the runner access to the Docker socket. &#8220;<em><span style=\"color: #808080;\">&#8211;docker-privileged<\/span><\/em>&#8221; allows the runner to access all devices on the host and processes outside the container (be careful).<\/p>\n\n\n<figure class=\"wp-block-gallery columns-2 is-cropped wp-block-gallery-1 is-layout-flex wp-block-gallery-is-layout-flex\"><ul class=\"blocks-gallery-grid\"><li class=\"blocks-gallery-item\"><figure><a href=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/availableRunners.png\"><img loading=\"lazy\" decoding=\"async\" width=\"358\" height=\"118\" data-attachment-id=\"21084\" data-permalink=\"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2021\/09\/11\/how-do-you-get-a-web-application-into-the-cloud\/availablerunners\/\" data-orig-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/availableRunners.png\" data-orig-size=\"358,118\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"availableRunners\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/availableRunners.png\" src=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/availableRunners.png\" alt=\"\" data-id=\"21084\" data-full-url=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/availableRunners.png\" data-link=\"https:\/\/blog.mi.hdm-stuttgart.de\/?attachment_id=21084\" class=\"wp-image-21084\" srcset=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/availableRunners.png 358w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/availableRunners-300x99.png 300w\" sizes=\"auto, (max-width: 358px) 100vw, 358px\" \/><\/a><\/figure><\/li><li class=\"blocks-gallery-item\"><figure><a href=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/pipeline.png\"><img loading=\"lazy\" decoding=\"async\" width=\"908\" height=\"212\" data-attachment-id=\"21085\" data-permalink=\"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2021\/09\/11\/how-do-you-get-a-web-application-into-the-cloud\/pipeline-4\/\" data-orig-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/pipeline.png\" data-orig-size=\"908,212\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"pipeline\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/pipeline.png\" src=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/pipeline.png\" alt=\"\" data-id=\"21085\" data-full-url=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/pipeline.png\" data-link=\"https:\/\/blog.mi.hdm-stuttgart.de\/?attachment_id=21085\" class=\"wp-image-21085\" srcset=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/pipeline.png 908w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/pipeline-300x70.png 300w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/pipeline-768x179.png 768w\" sizes=\"auto, (max-width: 908px) 100vw, 908px\" \/><\/a><\/figure><\/li><\/ul><\/figure>\n\n\n<h3><span data-preserver-spaces=\"true\">CI\/CD in GitHub<\/span><\/h3>\n<p><span data-preserver-spaces=\"true\">This is done by adding the following code in the GitHub repository in the self-created <span style=\"color: #808080;\"><em>.github\/workflows\/ci.yml<\/em><\/span> file. <br><\/span><span data-preserver-spaces=\"true\">Like the previous <em><span style=\"color: #808080;\">.gitlab-ci.yml<\/span><\/em> file, the script creates a Docker container and pushes it to Docker Hub. The <em><span style=\"color: #808080;\">DOCKER_USERNAME<\/span><\/em> and <em><span style=\"color: #808080;\">DOCKER_PASSWORD<\/span><\/em> are stored in the Action Secrets of GitHub (Settings &gt; Actions).<\/span><\/p>\n\n\n<div class=\"wp-block-jetpack-markdown\"><pre style=\"line-height: 1;font-size: 10px;\"><code class=\"language-yaml\" data-line=\"\">name: Build and Push to Docker.io\n\non:\n  push:\n    branches: [ master ]\n  pull_request:\n    branches: [ master ]\n\njobs:\n  build:\n\n    runs-on: ubuntu-latest\n\n    steps:\n    - uses: actions\/checkout@v2\n    - name: Login to Docker.io\n      run: docker login -u ${{ secrets.DOCKER_USERNAME }} -p ${{ secrets.DOCKER_PASSWORD }} \n \n    - name: Build Docker-Compose\n      run: docker-compose build\n \n    - name: Deploy Container to Docker.io\n      run: docker-compose push\n<\/code><\/pre>\n<\/div>\n\n\n\n<figure class=\"wp-block-gallery columns-3 is-cropped wp-block-gallery-2 is-layout-flex wp-block-gallery-is-layout-flex\"><ul class=\"blocks-gallery-grid\"><li class=\"blocks-gallery-item\"><figure><a href=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/github1.png\"><img loading=\"lazy\" decoding=\"async\" width=\"908\" height=\"234\" data-attachment-id=\"21086\" data-permalink=\"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2021\/09\/11\/how-do-you-get-a-web-application-into-the-cloud\/github1\/\" data-orig-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/github1.png\" data-orig-size=\"908,234\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"github1\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/github1.png\" src=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/github1.png\" alt=\"\" data-id=\"21086\" data-full-url=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/github1.png\" data-link=\"https:\/\/blog.mi.hdm-stuttgart.de\/?attachment_id=21086\" class=\"wp-image-21086\" srcset=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/github1.png 908w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/github1-300x77.png 300w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/github1-768x198.png 768w\" sizes=\"auto, (max-width: 908px) 100vw, 908px\" \/><\/a><\/figure><\/li><li class=\"blocks-gallery-item\"><figure><a href=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/github2.png\"><img loading=\"lazy\" decoding=\"async\" width=\"908\" height=\"506\" data-attachment-id=\"21087\" data-permalink=\"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2021\/09\/11\/how-do-you-get-a-web-application-into-the-cloud\/github2\/\" data-orig-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/github2.png\" data-orig-size=\"908,506\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"github2\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/github2.png\" src=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/github2.png\" alt=\"\" data-id=\"21087\" data-full-url=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/github2.png\" data-link=\"https:\/\/blog.mi.hdm-stuttgart.de\/?attachment_id=21087\" class=\"wp-image-21087\" srcset=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/github2.png 908w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/github2-300x167.png 300w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/github2-768x428.png 768w\" sizes=\"auto, (max-width: 908px) 100vw, 908px\" \/><\/a><\/figure><\/li><li class=\"blocks-gallery-item\"><figure><a href=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/github3.png\"><img loading=\"lazy\" decoding=\"async\" width=\"908\" height=\"318\" data-attachment-id=\"21088\" data-permalink=\"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2021\/09\/11\/how-do-you-get-a-web-application-into-the-cloud\/github3\/\" data-orig-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/github3.png\" data-orig-size=\"908,318\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"github3\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/github3.png\" src=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/github3.png\" alt=\"\" data-id=\"21088\" data-full-url=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/github3.png\" data-link=\"https:\/\/blog.mi.hdm-stuttgart.de\/?attachment_id=21088\" class=\"wp-image-21088\" srcset=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/github3.png 908w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/github3-300x105.png 300w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/github3-768x269.png 768w\" sizes=\"auto, (max-width: 908px) 100vw, 908px\" \/><\/a><\/figure><\/li><\/ul><\/figure>\n\n\n<h2>SSL<\/h2>\n<p>SSL is used to encrypt the data exchange between the web browser and web server. It thus protects against access by third parties. To set up SSL, it is necessary to have an SSL certificate.<\/p>\n<h3>Configuration<\/h3>\n<p>We decided to use &#8220;all-inkl.com&#8221; due to an existing subscription. <br>In the KAS admin center (after setting up the domains and subdomains), new DNS records can be created and edited (Domain &gt; DNS Settings &gt; Actions (Edit)). Here, a new Type-A record can be created that points to the IP address of the AWS reverse proxy. The email (which needed for verification) can easily be created in email &gt; email Inbox.<\/p>\n<h3><span data-preserver-spaces=\"true\">Server configuration&nbsp;<\/span><\/h3>\n<p><span data-preserver-spaces=\"true\">We used the free CA Let&#8217;s Encrypt (<\/span><a class=\"editor-rtfLink\" href=\"https:\/\/letsencrypt.org\/\" target=\"_blank\" rel=\"noopener\"><span data-preserver-spaces=\"true\">https:\/\/letsencrypt.org\/<\/span><\/a><span data-preserver-spaces=\"true\">) for the creation and renewal of the SSL certificates. For the configuration, we used the following images: <span style=\"color: #808080;\"><em>jwilder\/nginx-proxy<\/em><\/span> as Nginx Proxy and <em><span style=\"color: #808080;\">jrcs\/letsencrypt-nginx-proxy-companion<\/span><\/em> as Nginx Proxy Companion (it creates the certificates and mounts them via the volumes into the Nginx Proxy so that it can use them).&nbsp;&nbsp;<br><\/span><span data-preserver-spaces=\"true\">In the <em><span style=\"color: #808080;\">docker-compose.yml<\/span><\/em>, the environment variables can now be added for the service &#8220;frontend&#8221;.&nbsp;<\/span><\/p>\n\n\n<div class=\"wp-block-jetpack-markdown\"><pre style=\"line-height: 1;font-size: 10px;\"><code class=\"language-yaml\" data-line=\"\">  frontend:\n    image: dr079\/webshop:frontend\n    build:\n      context: .\/frontend\n      dockerfile: Dockerfile\n    restart: always\n    environment:\n      API_HOST: backend\n      API_PORT: 8080\n      # Subdomain\n      LETSENCRYPT_HOST: webshop.designmyhouse.de\n      # Email for domain verification\n      LETSENCRYPT_EMAIL: admin@designmyhouse.de\n      # For the Nginx proxy\n      VIRTUAL_HOST: webshop.designmyhouse.de\n      # The Port on which the frontend responds. Tells the Nginx proxy who to send the requests to.\n      VIRTUAL_PORT: 80\n# Not needed when deploying with reverse proxy\n#    ports:\n#      - &quot;80:80&quot;\n\n<\/code><\/pre>\n<\/div>\n\n\n<p>After that, we created the <span style=\"color: #808080;\"><em>docker-compose-cert.yml<\/em><\/span> file, which starts the Nginx Proxy and the Nginx Proxy Companion.<\/p>\n\n\n<div class=\"wp-block-jetpack-markdown\"><pre style=\"line-height: 1;font-size: 10px;\"><code class=\"language-yaml\" data-line=\"\">version: &quot;3.3&quot;\nservices:\n  nginxproxy:\n    image: jwilder\/nginx-proxy\n    restart: always\n    volumes:\n      - .\/nginx\/data\/certs:\/etc\/nginx\/certs\n      - .\/nginx\/conf:\/etc\/nginx\/conf.d\n      - .\/nginx\/dhparam:\/etc\/nginx\/dhparam\n      - .\/nginx\/data\/vhosts:\/etc\/nginx\/vhost.d\n      - .\/nginx\/data\/html:\/usr\/share\/nginx\/html\n      - \/var\/run\/docker.sock:\/tmp\/docker.sock\n    ports:\n      - 80:80\n      - 443:443\n    labels:\n      - &quot;com.github.jrcs.letsencrypt_nginx_proxy_companion.nginx_proxy&quot;\n\n  nginxproxy_comp:\n    image: jrcs\/letsencrypt-nginx-proxy-companion\n    restart: always\n    depends_on:\n      - nginxproxy\n    volumes:\n      - .\/nginx\/data\/certs:\/etc\/nginx\/certs:rw\n      - .\/nginx\/conf:\/etc\/nginx\/conf.d\n      - .\/nginx\/dhparam:\/etc\/nginx\/dhparam\n      - .\/nginx\/data\/vhosts:\/etc\/nginx\/vhost.d\n      - .\/nginx\/data\/html:\/usr\/share\/nginx\/html\n      - \/var\/run\/docker.sock:\/var\/run\/docker.sock:ro\n\n<\/code><\/pre>\n<\/div>\n\n\n<h3><span data-preserver-spaces=\"true\">AWS EC2 instance<\/span><\/h3>\n<p><span data-preserver-spaces=\"true\">In AWS, an EC2 instance (consisting of an Ubuntu server and a security group) can now be created and started with the settings Verify and Launch.&nbsp;<\/span><\/p>\n\n\n<figure class=\"wp-block-gallery columns-3 is-cropped wp-block-gallery-3 is-layout-flex wp-block-gallery-is-layout-flex\"><ul class=\"blocks-gallery-grid\"><li class=\"blocks-gallery-item\"><figure><a href=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/aws1.png\"><img loading=\"lazy\" decoding=\"async\" width=\"154\" height=\"26\" data-attachment-id=\"21090\" data-permalink=\"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2021\/09\/11\/how-do-you-get-a-web-application-into-the-cloud\/aws1\/\" data-orig-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/aws1.png\" data-orig-size=\"154,26\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"aws1\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/aws1.png\" src=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/aws1.png\" alt=\"\" data-id=\"21090\" data-full-url=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/aws1.png\" data-link=\"https:\/\/blog.mi.hdm-stuttgart.de\/?attachment_id=21090\" class=\"wp-image-21090\" srcset=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/aws1.png 154w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/aws1-150x26.png 150w\" sizes=\"auto, (max-width: 154px) 100vw, 154px\" \/><\/a><\/figure><\/li><li class=\"blocks-gallery-item\"><figure><a href=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/aws2.png\"><img loading=\"lazy\" decoding=\"async\" width=\"908\" height=\"72\" data-attachment-id=\"21091\" data-permalink=\"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2021\/09\/11\/how-do-you-get-a-web-application-into-the-cloud\/aws2\/\" data-orig-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/aws2.png\" data-orig-size=\"908,72\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"aws2\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/aws2.png\" src=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/aws2.png\" alt=\"\" data-id=\"21091\" data-full-url=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/aws2.png\" data-link=\"https:\/\/blog.mi.hdm-stuttgart.de\/?attachment_id=21091\" class=\"wp-image-21091\" srcset=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/aws2.png 908w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/aws2-300x24.png 300w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/aws2-768x61.png 768w\" sizes=\"auto, (max-width: 908px) 100vw, 908px\" \/><\/a><\/figure><\/li><li class=\"blocks-gallery-item\"><figure><a href=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/aws3.png\"><img loading=\"lazy\" decoding=\"async\" width=\"908\" height=\"24\" data-attachment-id=\"21092\" data-permalink=\"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2021\/09\/11\/how-do-you-get-a-web-application-into-the-cloud\/aws3\/\" data-orig-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/aws3.png\" data-orig-size=\"908,24\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"aws3\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/aws3.png\" src=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/aws3.png\" alt=\"\" data-id=\"21092\" data-full-url=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/aws3.png\" data-link=\"https:\/\/blog.mi.hdm-stuttgart.de\/?attachment_id=21092\" class=\"wp-image-21092\" srcset=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/aws3.png 908w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/aws3-300x8.png 300w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/aws3-768x20.png 768w\" sizes=\"auto, (max-width: 908px) 100vw, 908px\" \/><\/a><\/figure><\/li><li class=\"blocks-gallery-item\"><figure><a href=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/aws4.png\"><img loading=\"lazy\" decoding=\"async\" width=\"908\" height=\"72\" data-attachment-id=\"21093\" data-permalink=\"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2021\/09\/11\/how-do-you-get-a-web-application-into-the-cloud\/aws4\/\" data-orig-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/aws4.png\" data-orig-size=\"908,72\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"aws4\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/aws4.png\" src=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/aws4.png\" alt=\"\" data-id=\"21093\" data-full-url=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/aws4.png\" data-link=\"https:\/\/blog.mi.hdm-stuttgart.de\/?attachment_id=21093\" class=\"wp-image-21093\" srcset=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/aws4.png 908w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/aws4-300x24.png 300w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/aws4-768x61.png 768w\" sizes=\"auto, (max-width: 908px) 100vw, 908px\" \/><\/a><\/figure><\/li><li class=\"blocks-gallery-item\"><figure><a href=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/aws5.png\"><img loading=\"lazy\" decoding=\"async\" width=\"908\" height=\"252\" data-attachment-id=\"21094\" data-permalink=\"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2021\/09\/11\/how-do-you-get-a-web-application-into-the-cloud\/aws5\/\" data-orig-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/aws5.png\" data-orig-size=\"908,252\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"aws5\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/aws5.png\" src=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/aws5.png\" alt=\"\" data-id=\"21094\" data-full-url=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/aws5.png\" data-link=\"https:\/\/blog.mi.hdm-stuttgart.de\/?attachment_id=21094\" class=\"wp-image-21094\" srcset=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/aws5.png 908w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/aws5-300x83.png 300w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/aws5-768x213.png 768w\" sizes=\"auto, (max-width: 908px) 100vw, 908px\" \/><\/a><\/figure><\/li><\/ul><\/figure>\n\n\n<p>The IP address of the created instance can now be entered as a Type-A entry under &#8220;all-inkl.com&#8221;.<\/p>\n\n\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/all-inkl.png\"><img loading=\"lazy\" decoding=\"async\" width=\"908\" height=\"264\" data-attachment-id=\"21095\" data-permalink=\"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2021\/09\/11\/how-do-you-get-a-web-application-into-the-cloud\/all-inkl\/\" data-orig-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/all-inkl.png\" data-orig-size=\"908,264\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"all-inkl\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/all-inkl.png\" src=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/all-inkl.png\" alt=\"\" class=\"wp-image-21095\" srcset=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/all-inkl.png 908w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/all-inkl-300x87.png 300w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/all-inkl-768x223.png 768w\" sizes=\"auto, (max-width: 908px) 100vw, 908px\" \/><\/a><\/figure>\n\n\n<h3><span data-preserver-spaces=\"true\">Install Docker on Ubuntu<\/span><\/h3>\n<p><span data-preserver-spaces=\"true\">It is now possible to connect to the EC2 instance and run the following commands to make the project accessible through the domain\/subdomain. (<\/span><em><span data-preserver-spaces=\"true\">Note<\/span><\/em><span data-preserver-spaces=\"true\">: It may take a few hours for the DNS server to apply the settings.&nbsp;<\/span><em><span data-preserver-spaces=\"true\">Solution<\/span><\/em><span data-preserver-spaces=\"true\">: Use the Tor browser)<\/span><\/p>\n\n\n<div class=\"wp-block-jetpack-markdown\"><pre style=\"line-height: 1;font-size: 10px;\"><code class=\"\" data-line=\"\"># Add GPG key of Docker repository from APT sources.\ncurl -fsSL https:\/\/download.docker.com\/linux\/ubuntu\/gpg | sudo apt-key add -\n\nsudo add-apt-repository &quot;deb [arch=amd64] https:\/\/download.docker.com\/linux\/ubuntu $(lsb_release -cs) stable&quot;\n\n# Update Ubuntu package database\nsudo apt-get update\n\n# Install Docker\nsudo apt-get install -y docker-ce\n\n# Install Docker Compose\nsudo curl -L https:\/\/github.com\/docker\/compose\/releases\/download\/1.18.0\/docker-compose-`uname -s`-`uname -m` -o \/usr\/local\/bin\/docker-compose\n\n# Give Docker Compose the execute permission\nsudo chmod +x \/usr\/local\/bin\/docker-compose\n\n# Log in as root user\nsudo -s\n\n# Clone project\ngit clone https:\/\/github.com\/user_name\/project_name.git\n\n# Build and launch project\ndocker-compose -f .\/project_name\/docker-compose-cert.yml up --build -d\n\n# Pull images from DockerHub\nsudo docker-compose -f .\/cloud-webshop\/docker-compose.yml pull\n\nsudo docker-compose -f .\/cloud-webshop\/docker-compose.yml up -d\n\n<\/code><\/pre>\n<\/div>\n\n\n<h2><span data-preserver-spaces=\"true\">Watchtower<\/span><\/h2>\n<p><span data-preserver-spaces=\"true\">With Watchtower, updates to the Docker registry can be automatically detected and downloaded. The container will then be rebooted with the new image. Watchtower accesses the Docker repo via <em><span style=\"color: #808080;\">REPO_USER<\/span> <\/em>&amp;<span style=\"color: #808080;\"><em> REPO_PASS<\/em><\/span> and checks in the set time interval (<em><span style=\"color: #808080;\">&#8212; interval 30<\/span><\/em>) if the Docker images have changed and updates them on the fly.<br><\/span><span data-preserver-spaces=\"true\">This requires adding the following code to the <em><span style=\"color: #808080;\">docker-compose.yml<\/span> <\/em>(replace <em><span style=\"color: #808080;\">REPO_USER<\/span><\/em> and <em><span style=\"color: #808080;\">REPO_PASS<\/span><\/em> with Docker.io Access Token credentials (Settings &gt; Security)).<\/span><\/p>\n\n\n<div class=\"wp-block-jetpack-markdown\"><pre style=\"line-height: 1;font-size: 10px;\"><code class=\"language-yaml\" data-line=\"\">  watchtower:\n    image: v2tec\/watchtower\n    environment:\n      REPO_USER: REPO_USER\n      REPO_PASS: REPO_PASS\n    volumes:\n      - \/var\/run\/docker.sock:\/var\/run\/docker.sock\n    command: --interval 30\n<\/code><\/pre>\n<\/div>\n\n\n<h2><span data-preserver-spaces=\"true\">Terraform<\/span><\/h2>\n<p><span data-preserver-spaces=\"true\">The preceding steps involve a considerable manual effort. However, it is possible to automate this, e.g., with Terraform. To achieve this, the following files must be written.<\/span><\/p>\n\n\n<p><strong>main.tf<\/strong><\/p>\n\n\n\n<div class=\"wp-block-jetpack-markdown\"><pre style=\"line-height: 1;font-size: 10px;\"><code class=\"\" data-line=\"\">resource &quot;aws_instance&quot; &quot;test&quot; {\n  ami           = data.aws_ami.ubuntu.id\n  instance_type = var.ec2_instance_type\n\n  tags = {\n    Name = var.ec2_tags\n  }\n\n  user_data = file(&quot;docker\/install.sh&quot;)\n\/\/  user_data = file(&quot;docker\/setupRunner.sh&quot;)\n  key_name = aws_key_pair.generated_key.key_name\n  security_groups = [\n    aws_security_group.allow_http.name,\n    aws_security_group.allow_https.name,\n    aws_security_group.allow_ssh.name]\n}\n\noutput &quot;instance_ips&quot; {\n  value = aws_instance.test.*.public_ip\n}\n<\/code><\/pre>\n<\/div>\n\n\n\n<p><strong>providers.tf<\/strong><\/p>\n\n\n\n<div class=\"wp-block-jetpack-markdown\"><pre style=\"line-height: 1;font-size: 10px;\"><code class=\"\" data-line=\"\">provider &quot;aws&quot; {\n  access_key = var.aws-access-key\n  secret_key = var.aws-secret-key\n  region = var.aws-region\n}\n<\/code><\/pre>\n<\/div>\n\n\n\n<p><strong>security_groups.tf<\/strong><\/p>\n\n\n\n<div class=\"wp-block-jetpack-markdown\"><pre style=\"line-height: 1;font-size: 10px;\"><code class=\"\" data-line=\"\">resource &quot;aws_security_group&quot; &quot;allow_http&quot; {\n  name = &quot;allow_http&quot;\n  description = &quot;Allow http inbound traffic&quot;\n  vpc_id = aws_default_vpc.default.id\n\n  ingress {\n    from_port = 80\n    to_port = 80\n    protocol = &quot;tcp&quot;\n    cidr_blocks = [\n      &quot;0.0.0.0\/0&quot;\n    ]\n  }\n\n  egress {\n    from_port = 0\n    to_port = 0\n    protocol = &quot;-1&quot;\n    cidr_blocks = [\n      &quot;0.0.0.0\/0&quot;]\n  }\n}\n\nresource &quot;aws_security_group&quot; &quot;allow_https&quot; {\n  name = &quot;allow_https&quot;\n  description = &quot;Allow https inbound traffic&quot;\n  vpc_id = aws_default_vpc.default.id\n\n  ingress {\n    from_port = 443\n    to_port = 443\n    protocol = &quot;tcp&quot;\n    cidr_blocks = [\n      &quot;0.0.0.0\/0&quot;\n    ]\n  }\n\n  egress {\n    from_port = 0\n    to_port = 0\n    protocol = &quot;-1&quot;\n    cidr_blocks = [\n      &quot;0.0.0.0\/0&quot;]\n  }\n}\n\nresource &quot;aws_security_group&quot; &quot;allow_ssh&quot; {\n  name = &quot;allow_ssh&quot;\n  description = &quot;Allow ssh inbound traffic&quot;\n  vpc_id = aws_default_vpc.default.id\n\n  ingress {\n    from_port = 22\n    to_port = 22\n    protocol = &quot;tcp&quot;\n    # To keep this example simple, we allow incoming SSH requests from any IP. In real-world usage, you should only\n    # allow SSH requests from trusted servers, such as a bastion host or VPN server.\n    cidr_blocks = [\n      &quot;0.0.0.0\/0&quot;\n    ]\n  }\n}\n<\/code><\/pre>\n<\/div>\n\n\n\n<p><strong>variables.tf<\/strong><\/p>\n\n\n\n<div class=\"wp-block-jetpack-markdown\"><pre style=\"line-height: 1;font-size: 10px;\"><code class=\"\" data-line=\"\">variable &quot;ec2_instance_type&quot; {\n  default = &quot;t2.micro&quot;\n}\n\nvariable &quot;ec2_tags&quot; {\n  default = &quot;Webshop&quot;\n\/\/  default = &quot;Gitlab-Runner&quot;\n}\n\nvariable &quot;ec2_count&quot; {\n  default = &quot;1&quot;\n}\n\n\ndata &quot;aws_ami&quot; &quot;ubuntu&quot; {\n  most_recent = true\n  filter {\n    name   = &quot;name&quot;\n    values = [&quot;ubuntu\/images\/hvm-ssd\/ubuntu-focal-20.04-amd64-server-*&quot;]\n  }\n  filter {\n    name   = &quot;virtualization-type&quot;\n    values = [&quot;hvm&quot;]\n  }\n  owners = [&quot;099720109477&quot;] # Canonical\n}\n<\/code><\/pre>\n<\/div>\n\n\n\n<p><strong>ssh_key.tf<\/strong><\/p>\n\n\n\n<div class=\"wp-block-jetpack-markdown\"><pre style=\"line-height: 1;font-size: 10px;\"><code class=\"\" data-line=\"\">variable &quot;key_name&quot; {\n  default = &quot;Webshop&quot;\n}\n\nresource &quot;tls_private_key&quot; &quot;example&quot; {\n  algorithm = &quot;RSA&quot;\n  rsa_bits = 4096\n}\n\nresource &quot;aws_key_pair&quot; &quot;generated_key&quot; {\n  key_name = var.key_name\n  public_key = tls_private_key.example.public_key_openssh\n}\n\nresource &quot;aws_default_vpc&quot; &quot;default&quot; {\n  tags = {\n    Name = &quot;Default VPC&quot;\n  }\n}\n<\/code><\/pre>\n<\/div>\n\n\n\n<p><strong>variable_secrets.tf<\/strong><\/p>\n\n\n\n<div class=\"wp-block-jetpack-markdown\"><pre style=\"line-height: 1;font-size: 10px;\"><code class=\"\" data-line=\"\">variable &quot;aws-access-key&quot; {\n  type = string\n  default = &quot;aws-access-key&quot;\n}\n\nvariable &quot;aws-secret-key&quot; {\n  type = string\n  default = &quot;aws-secret-key&quot; \n}\n\nvariable &quot;aws-region&quot; {\n  type = string\n  default = &quot;eu-central-1&quot;\n}\n<\/code><\/pre>\n<\/div>\n\n\n<h3><span data-preserver-spaces=\"true\">install.sh for EC2 setup<\/span><\/h3>\n<p><span data-preserver-spaces=\"true\">To do this, we created a <span style=\"color: #808080;\"><em>.\/docker\/install.sh<\/em><\/span> file with the following content.<\/span><\/p>\n\n\n<div class=\"wp-block-jetpack-markdown\"><pre style=\"line-height: 1;font-size: 10px;\"><code class=\"language-bash\" data-line=\"\">\n#!\/bin\/bash\n\n# Install wget to update IP at all-inkl.com\necho &quot;Setup all-inkl.com&quot;\nsudo apt-get install wget\n\n# Save public IP to variable\nip=&quot;$(dig +short myip.opendns.com @resolver1.opendns.com)&quot;\n\n# Add all-inkl.com variables\nkas_login=&quot;username&quot;\nkas_auth_data=&quot;pw&quot;\nkas_action=&quot;update_dns_settings&quot;\nsub_domain=&quot;sub&quot;\nrecord_id=&quot;id&quot;\n\nsudo sleep 10s\n\n# Update all-inkl.com dns-settings with current IP and account data\nsudo wget --no-check-certificate --quiet \\\n  --method POST \\\n  --timeout=0 \\\n  --header &#039;&#039; \\\n    &#039;https:\/\/kasapi.kasserver.com\/dokumentation\/formular.php?kas_login=&#039;&quot;${kas_login}&quot;&#039;&amp;kas_auth_type=plain&amp;kas_auth_data=&#039;&quot;${kas_auth_data}&quot;&#039;&amp;kas_action=&#039;&quot;${kas_action}&quot;&#039;&amp;var1=record_name&amp;wert1=&#039;&quot;${sub_domain}&quot;&#039;&amp;var2=record_type&amp;wert2=A&amp;var3=record_data&amp;wert3=&#039;&quot;${ip}&quot;&#039;&amp;var4=record_id&amp;wert4=&#039;&quot;${record_id}&quot;&#039;&amp;anz_var=4&#039;\n\n\necho &quot;Installing Docker&quot;\ncurl -fsSL https:\/\/download.docker.com\/linux\/ubuntu\/gpg | sudo apt-key add -\nsudo add-apt-repository &quot;deb [arch=amd64] https:\/\/download.docker.com\/linux\/ubuntu $(lsb_release -cs) stable&quot;\nsudo apt-get update\nsudo apt-get install -y docker-ce\n\necho &quot;Installing Docker-Compose&quot;\nsudo curl -L https:\/\/github.com\/docker\/compose\/releases\/download\/1.18.0\/docker-compose-`uname -s`-`uname -m` -o \/usr\/local\/bin\/docker-compose\nsudo chmod +x \/usr\/local\/bin\/docker-compose\n\n# Follow guide to create personal access token https:\/\/docs.github.com\/en\/github\/authenticating-to-github\/keeping-your-account-and-data-secure\/creating-a-personal-access-token\nsudo git clone https:\/\/username:token@github.com\/ratzel921\/cloud-webshop.git\nsudo docker login -u username -p token\nsudo docker-compose -f .\/cloud-webshop\/docker-compose-cert.yml up --build -d\nsudo docker-compose -f .\/cloud-webshop\/docker-compose.yml pull\nsudo docker-compose -f .\/cloud-webshop\/docker-compose.yml up\n<\/code><\/pre>\n<\/div>\n\n\n<p>Next, run the following commands. This will automatically create an EC2 instance (runs the application), a Security_Group (for connections to the EC2 instance via HTTPS, HTTP, and SSH), an SSH_KEY (allows to access the EC2 instance via SSH). In the end, the IP address of the EC2 instance is displayed in the console. This will automatically be entered into all-inkl.com or manually add it.<\/p>\n\n\n<div class=\"wp-block-jetpack-markdown\"><pre style=\"line-height: 1;font-size: 10px;\"><code class=\"\" data-line=\"\"># Get terraform provider with init and use apply to start the terraform script.\nterraform init\nterraform apply --auto-approve\n\n# (Optional) Delete EC2 instances\nterraform destroy --auto-approve\n\n<\/code><\/pre>\n<\/div>\n\n\n\n<figure class=\"wp-block-gallery columns-3 is-cropped wp-block-gallery-4 is-layout-flex wp-block-gallery-is-layout-flex\"><ul class=\"blocks-gallery-grid\"><li class=\"blocks-gallery-item\"><figure><a href=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/terraform1.png\"><img loading=\"lazy\" decoding=\"async\" width=\"620\" height=\"280\" data-attachment-id=\"21097\" data-permalink=\"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2021\/09\/11\/how-do-you-get-a-web-application-into-the-cloud\/terraform1\/\" data-orig-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/terraform1.png\" data-orig-size=\"620,280\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"terraform1\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/terraform1.png\" src=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/terraform1.png\" alt=\"\" data-id=\"21097\" data-full-url=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/terraform1.png\" data-link=\"https:\/\/blog.mi.hdm-stuttgart.de\/?attachment_id=21097\" class=\"wp-image-21097\" srcset=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/terraform1.png 620w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/terraform1-300x135.png 300w\" sizes=\"auto, (max-width: 620px) 100vw, 620px\" \/><\/a><\/figure><\/li><li class=\"blocks-gallery-item\"><figure><a href=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/terraform2.png\"><img loading=\"lazy\" decoding=\"async\" width=\"906\" height=\"148\" data-attachment-id=\"21098\" data-permalink=\"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2021\/09\/11\/how-do-you-get-a-web-application-into-the-cloud\/terraform2\/\" data-orig-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/terraform2.png\" data-orig-size=\"906,148\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"terraform2\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/terraform2.png\" src=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/terraform2.png\" alt=\"\" data-id=\"21098\" data-full-url=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/terraform2.png\" data-link=\"https:\/\/blog.mi.hdm-stuttgart.de\/?attachment_id=21098\" class=\"wp-image-21098\" srcset=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/terraform2.png 906w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/terraform2-300x49.png 300w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/terraform2-768x125.png 768w\" sizes=\"auto, (max-width: 906px) 100vw, 906px\" \/><\/a><\/figure><\/li><li class=\"blocks-gallery-item\"><figure><a href=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/terraform3.png\"><img loading=\"lazy\" decoding=\"async\" width=\"720\" height=\"114\" data-attachment-id=\"21099\" data-permalink=\"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2021\/09\/11\/how-do-you-get-a-web-application-into-the-cloud\/terraform3\/\" data-orig-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/terraform3.png\" data-orig-size=\"720,114\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"terraform3\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/terraform3.png\" src=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/terraform3.png\" alt=\"\" data-id=\"21099\" data-full-url=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/terraform3.png\" data-link=\"https:\/\/blog.mi.hdm-stuttgart.de\/?attachment_id=21099\" class=\"wp-image-21099\" srcset=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/terraform3.png 720w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/terraform3-300x48.png 300w\" sizes=\"auto, (max-width: 720px) 100vw, 720px\" \/><\/a><\/figure><\/li><\/ul><\/figure>\n\n\n<h2><span data-preserver-spaces=\"true\">Testing<\/span><\/h2>\n<h3><span data-preserver-spaces=\"true\">Creating a Testing Environment<\/span><\/h3>\n<p><span data-preserver-spaces=\"true\">Using Terraform and an EC2 instance, it is also possible to create a testing environment. We used the GitHub pipeline for this.<\/span><\/p>\n\n\n<p><strong>Backend\/Dockerfile<\/strong><\/p>\n\n\n\n<div class=\"wp-block-jetpack-markdown\"><pre style=\"line-height: 1;font-size: 10px;\"><code class=\"\" data-line=\"\"># Build stage\nFROM maven:3.6.3-jdk-8-slim AS build\nCOPY src \/home\/app\/src\nCOPY pom.xml \/home\/app\nRUN mvn -f \/home\/app\/pom.xml clean test\nRUN mvn -f \/home\/app\/pom.xml clean package\n\n# Package stage\nFROM openjdk:8-jre-slim\nCOPY --from=build \/home\/app\/target\/*.jar \/usr\/local\/backend.jar\nCOPY --from=build \/home\/app\/target\/lib\/*.jar \/usr\/local\/lib\/\nEXPOSE 8080\nENTRYPOINT [&quot;java&quot;,&quot;-jar&quot;,&quot;\/usr\/local\/backend.jar&quot;]\n<\/code><\/pre>\n<\/div>\n\n\n\n<p><strong>frontend\/nginx\/nginx.conf<\/strong><\/p>\n\n\n\n<div class=\"wp-block-jetpack-markdown\"><pre style=\"line-height: 1;font-size: 10px;\"><code class=\"\" data-line=\"\">server {\n  listen 80;\n  server_name www.${VIRTUAL_HOST} ${VIRTUAL_HOST};\n\n    location \/ {\n        root   \/usr\/share\/nginx\/html;\n        index  index.html index.htm;\n        try_files $uri $uri\/ \/index.html;\n        proxy_cookie_path \/ &quot;\/; SameSite=lax; HTTPOnly; Secure&quot;;\n    }\n\n    location \/api {\n        proxy_set_header X-Real-IP $remote_addr;\n        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n        proxy_set_header Host $http_host;\n        proxy_set_header X-NginX-Proxy true;\n\n        proxy_pass_header Set-Cookie;\n\n        proxy_cookie_domain www.${VIRTUAL_HOST} ${VIRTUAL_HOST};\n        #rewrite ^\/api\/?(.*) \/$1 break;\n        proxy_pass http:\/\/${API_HOST}:${API_PORT};\n        proxy_redirect off;\n    }\n\n   error_page   500 502 503 504  \/50x.html;\n\n   location = \/50x.html {\n        root   \/usr\/share\/nginx\/html;\n    }\n}\n<\/code><\/pre>\n<\/div>\n\n\n\n<p><strong>frontend\/Dockerfile<\/strong><\/p>\n\n\n\n<div class=\"wp-block-jetpack-markdown\"><pre style=\"line-height: 1;font-size: 10px;\"><code class=\"\" data-line=\"\"># Build stage\n# Use node:alpine to build static files\nFROM node:15.14-alpine as build-stage\n\n# Create app directory\nWORKDIR \/usr\/src\/app\n\n# Install other dependencies via apk\nRUN apk update &amp;&amp; apk add python g++ make &amp;&amp; rm -rf \/var\/cache\/apk\/*\n\n# Install app dependencies\n# A wildcard is used to ensure both package.json AND package-lock.json are copied\n# where available (npm@5+)\nCOPY package*.json .\/\n\nRUN npm install\n\n# Bundle app source\nCOPY . .\n\n# Build static files\nRUN npm run test\nRUN npm run build\n\n\n# Package stage\n# Use nginx alpine for minimal image size\nFROM nginx:stable-alpine as production-stage\n\n# Copy static files from build-side to build-server\nCOPY --from=build-stage \/usr\/src\/app\/dist \/usr\/share\/nginx\/html\n\nRUN rm \/etc\/nginx\/conf.d\/default.conf\nCOPY nginx\/nginx.conf \/etc\/nginx\/templates\/\n\n# EXPOSE 80\nCMD [&quot;\/bin\/sh&quot; , &quot;-c&quot; , &quot;envsubst &#039;${API_HOST} ${API_PORT} ${VIRTUAL_HOST}&#039; &lt; \/etc\/nginx\/templates\/nginx.conf &gt; \/etc\/nginx\/conf.d\/nginx.conf &amp;&amp; exec nginx -g &#039;daemon off;&#039;&quot;]\n<\/code><\/pre>\n<\/div>\n\n\n<h4><span data-preserver-spaces=\"true\">Modifying the docker-compose.yml<\/span><\/h4>\n<p><span data-preserver-spaces=\"true\">To do this, we created a copy of <span style=\"color: #808080;\"><em>docker-compose.yml<\/em><\/span> (<span style=\"color: #808080;\"><em>docker-compose-testStage.yml<\/em><\/span>). We changed the images and the <span style=\"color: #808080;\"><em>LETSENCRYPT_HOST<\/em><\/span> &amp; <span style=\"color: #808080;\"><em>VIRTUAL_HOST<\/em><\/span> for the \u201cbackend\u201d and \u201cfrontend\u201d service in this file.<\/span><\/p>\n<h3><span data-preserver-spaces=\"true\">Modifying the Terraform files<\/span><\/h3>\n<p><span data-preserver-spaces=\"true\">In the <span style=\"color: #808080;\"><em>testStage.sh<\/em><\/span>, we changed the <em><span style=\"color: #808080;\">record_id<\/span><\/em> and &#8220;<span style=\"color: #808080;\"><em>docker-compose -f .\/cloud-webshop\/docker-compose.yml pull &amp; <\/em><\/span><\/span><span data-preserver-spaces=\"true\"><span style=\"color: #808080;\"><em>sudo docker-compose -f .\/cloud-webshop\/docker-compose.yml up -d<\/em><\/span>&#8221; to &#8220;<span style=\"color: #808080;\"><em>sudo docker-compose -f .\/cloud-webshop\/docker-compose-testStage.yml pull <\/em><\/span><\/span><span data-preserver-spaces=\"true\"><span style=\"color: #808080;\"><em>sudo docker-compose -f .\/cloud-webshop\/docker-compose-testStage.yml up -d<\/em><\/span>&#8220;<br><\/span><span data-preserver-spaces=\"true\">In the <span style=\"color: #808080;\"><em>main.tf<\/em><\/span>, &#8220;<span style=\"color: #808080;\"><em>user_date = file(&#8220;docker\/test_Stage.sh&#8221;)<\/em><\/span>&#8221; is set.<br><\/span><span data-preserver-spaces=\"true\">After that, the EC2 instance, the security group, and SSH can be started as usual using Terraform.<\/span><\/p>\n\n\n<figure class=\"wp-block-gallery columns-2 is-cropped wp-block-gallery-5 is-layout-flex wp-block-gallery-is-layout-flex\"><ul class=\"blocks-gallery-grid\"><li class=\"blocks-gallery-item\"><figure><a href=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/testEnvironment1.png\"><img loading=\"lazy\" decoding=\"async\" width=\"908\" height=\"356\" data-attachment-id=\"21100\" data-permalink=\"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2021\/09\/11\/how-do-you-get-a-web-application-into-the-cloud\/testenvironment1\/\" data-orig-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/testEnvironment1.png\" data-orig-size=\"908,356\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"testEnvironment1\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/testEnvironment1.png\" src=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/testEnvironment1.png\" alt=\"\" data-id=\"21100\" data-full-url=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/testEnvironment1.png\" data-link=\"https:\/\/blog.mi.hdm-stuttgart.de\/?attachment_id=21100\" class=\"wp-image-21100\" srcset=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/testEnvironment1.png 908w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/testEnvironment1-300x118.png 300w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/testEnvironment1-768x301.png 768w\" sizes=\"auto, (max-width: 908px) 100vw, 908px\" \/><\/a><\/figure><\/li><li class=\"blocks-gallery-item\"><figure><a href=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/testEnvironment2.png\"><img loading=\"lazy\" decoding=\"async\" width=\"366\" height=\"84\" data-attachment-id=\"21101\" data-permalink=\"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2021\/09\/11\/how-do-you-get-a-web-application-into-the-cloud\/testenvironment2\/\" data-orig-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/testEnvironment2.png\" data-orig-size=\"366,84\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"testEnvironment2\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/testEnvironment2.png\" src=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/testEnvironment2.png\" alt=\"\" data-id=\"21101\" data-full-url=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/testEnvironment2.png\" data-link=\"https:\/\/blog.mi.hdm-stuttgart.de\/?attachment_id=21101\" class=\"wp-image-21101\" srcset=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/testEnvironment2.png 366w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/testEnvironment2-300x69.png 300w\" sizes=\"auto, (max-width: 366px) 100vw, 366px\" \/><\/a><\/figure><\/li><\/ul><\/figure>\n\n\n<h3><span data-preserver-spaces=\"true\">Automated Selenium frontend testing with GitHub&nbsp;<\/span><\/h3>\n<p><span data-preserver-spaces=\"true\">To do this, create the <span style=\"color: #808080;\"><em>.github\/workflows\/selenium.yml<\/em><\/span> file with the following content.<br><\/span><span data-preserver-spaces=\"true\">The script is executed on every push to the repository. It installs all necessary packages, creates a screenshot folder, and runs the pre-programmed Selenium tests located in the frontend folder.<br><\/span><span data-preserver-spaces=\"true\">After a push or manual execution, the test results with the artifacts (screenshots) are located on the Actions tab.<\/span><\/p>\n\n\n<div class=\"wp-block-jetpack-markdown\"><pre style=\"line-height: 1;font-size: 10px;\"><code class=\"language-yaml\" data-line=\"\">name: selenium tests\non: push\njobs:\n  test:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions\/checkout@v2\n      - name: Build the stack\n        run: docker-compose up -d\n      - name: npm install\n        run: cd frontend &amp;&amp; npm install\n      - name: install jest\n        run: cd frontend &amp;&amp; npm install jest\n      - name: install selenium-webdriver\n        run: cd frontend &amp;&amp; npm install selenium-webdriver\n      - name: run tests\n        run: mkdir -p \/tmp\/screenshots\/ &amp;&amp; cd frontend &amp;&amp; npm test\n      - name: Archive screenshots\n        uses: actions\/upload-artifact@v2\n        with:\n          name: selenium-screenshots\n          path: \/tmp\/screenshots\/\n      - name: Shutdown\n        run: docker-compose down\n<\/code><\/pre>\n<\/div>\n\n\n\n<p>Note that Chromedriver must be run headless, as GitHub cannot run a browser on a screen.<\/p>\n\n\n\n<div class=\"wp-block-jetpack-markdown\"><pre style=\"line-height: 1;font-size: 10px;\"><code class=\"\" data-line=\"\">var driver = await new Builder()\n        .forBrowser(&#039;chrome&#039;)\n        .setChromeOptions(new chrome.Options().headless())\n        .build();\n<\/code><\/pre>\n<\/div>\n\n\n\n<figure class=\"wp-block-gallery columns-2 is-cropped wp-block-gallery-6 is-layout-flex wp-block-gallery-is-layout-flex\"><ul class=\"blocks-gallery-grid\"><li class=\"blocks-gallery-item\"><figure><a href=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/Selenium1.png\"><img loading=\"lazy\" decoding=\"async\" width=\"908\" height=\"332\" data-attachment-id=\"21102\" data-permalink=\"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2021\/09\/11\/how-do-you-get-a-web-application-into-the-cloud\/selenium1\/\" data-orig-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/Selenium1.png\" data-orig-size=\"908,332\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"Selenium1\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/Selenium1.png\" src=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/Selenium1.png\" alt=\"\" data-id=\"21102\" data-full-url=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/Selenium1.png\" data-link=\"https:\/\/blog.mi.hdm-stuttgart.de\/?attachment_id=21102\" class=\"wp-image-21102\" srcset=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/Selenium1.png 908w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/Selenium1-300x110.png 300w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/Selenium1-768x281.png 768w\" sizes=\"auto, (max-width: 908px) 100vw, 908px\" \/><\/a><\/figure><\/li><li class=\"blocks-gallery-item\"><figure><a href=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/Selenium2.png\"><img loading=\"lazy\" decoding=\"async\" width=\"636\" height=\"520\" data-attachment-id=\"21103\" data-permalink=\"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2021\/09\/11\/how-do-you-get-a-web-application-into-the-cloud\/selenium2\/\" data-orig-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/Selenium2.png\" data-orig-size=\"636,520\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"Selenium2\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/Selenium2.png\" src=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/Selenium2.png\" alt=\"\" data-id=\"21103\" data-full-url=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/Selenium2.png\" data-link=\"https:\/\/blog.mi.hdm-stuttgart.de\/?attachment_id=21103\" class=\"wp-image-21103\" srcset=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/Selenium2.png 636w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/Selenium2-300x245.png 300w\" sizes=\"auto, (max-width: 636px) 100vw, 636px\" \/><\/a><\/figure><\/li><\/ul><\/figure>\n\n\n<h2><span data-preserver-spaces=\"true\">Infrastructure as a Code<\/span><\/h2>\n<p><span data-preserver-spaces=\"true\">Cloud computing is the on-demand provision of IT resources (e.g., servers, storage, databases) via the Internet. Cloud computing resources can be scaled up or down depending on business requirements. You only pay for the IT resources you use.<\/span><span data-preserver-spaces=\"true\">&nbsp;<br>On July 27, 2021, Gartner published the latest &#8220;Magic Quadrant&#8221; for Cloud Infrastructure and Platform Services. Like last year, Amazon Web Service is the top performer in the Magic Quadrant. Followed by Microsoft and Google. (<\/span><a class=\"editor-rtfLink\" href=\"https:\/\/www.gartner.com\/doc\/reprints?id=1-271OE4VR&amp;ct=210802&amp;st=sb\" target=\"_blank\" rel=\"noopener\"><span data-preserver-spaces=\"true\">https:\/\/www.gartner.com\/doc\/reprints?id=1-271OE4VR&amp;ct=210802&amp;st=sb<\/span><\/a><span data-preserver-spaces=\"true\">). Since we were interested in trying Docker Compose, we decided to use AWS for deployment.<\/span><\/p>\n<h3><span data-preserver-spaces=\"true\">Deployment on Amazon ECS with Docker Compose&nbsp;<\/span><\/h3>\n<p><span data-preserver-spaces=\"true\">Since early 2020, AWS and Docker have started working on an open Docker Compose specification, which will make it possible to use the Docker Compose format to deploy containers on Amazon ECS and AWS Fargate. In July 2020, the first beta version for Docker Desktop was released; the first stable version has been available since September 15, 2020.<\/span><\/p>\n<h4><span data-preserver-spaces=\"true\">Customize docker-compose.yml<\/span><\/h4>\n<p><span data-preserver-spaces=\"true\">The AWS ECS CLI supports Compose versions 1, 2, and 3. By default, it looks for <span style=\"color: #808080;\"><em>docker-compose.yml<\/em><\/span> in the current directory. Optionally, you can specify a different filename or path to a Compose file with the <span style=\"color: #808080;\"><em>&#8211;file<\/em><\/span> option. The Amazon ECS CLI only supports a few parameters, so correcting the yml may be necessary (<\/span><a class=\"editor-rtfLink\" href=\"https:\/\/docs.aws.amazon.com\/AmazonECS\/latest\/developerguide\/cmd-ecs-cli-compose-parameters.html\" target=\"_blank\" rel=\"noopener\"><span data-preserver-spaces=\"true\">https:\/\/docs.aws.amazon.com\/AmazonECS\/latest\/developerguide\/cmd-ecs-cli-compose-parameters.html<\/span><\/a><span data-preserver-spaces=\"true\">).<\/span><\/p>\n\n\n<div class=\"wp-block-jetpack-markdown\"><pre style=\"line-height: 1;font-size: 10px;\"><code class=\"\" data-line=\"\"># (Optional) Create a new Docker context to point the Docker CLI to the correct endpoint. For this step you need the AWS_ACCESS_KEY and AWS_SECRET_ACCESS_KEY.\ndocker context create ecs myecscontext\n\n# (Optional) Use context\ndocker context use myecscontext\n\n# Deploy application to AWS\ndocker compose up \n\n# Here you can see which containers were started as well as the URLs\ndocker compose ps\n\n# (Optional) Shut down container. (Don&#039;t forget to change the context back to default).\ndocker compose down\n\n# Convert Docker Compose file to CloudFormation to track which resources are created or updated\ndocker compose convert\n<\/code><\/pre>\n<\/div>\n\n\n<h2><span data-preserver-spaces=\"true\">BuildX<\/span><\/h2>\n<h3><span data-preserver-spaces=\"true\">Building images for other processors<\/span><\/h3>\n<p><span data-preserver-spaces=\"true\">For example, if you have an M1 with an arm64 processor, a locally created image would not be accepted by AWS (error message &#8220;EssentialContainerExited: Essential container in task exited&#8221;). The reason is that ECS instances only support amd64 images.<\/span><\/p>\n<p><span data-preserver-spaces=\"true\">Since Docker version &gt;= 19.03, Docker offers buildX. The plugin is officially no longer considered experimental as of August 5, 2020. With the buildX functionality, it is relatively easy to create Docker images that work on multiple CPU architectures.<\/span><\/p>\n\n\n<div class=\"wp-block-jetpack-markdown\"><pre style=\"line-height: 1;font-size: 10px;\"><code class=\"\" data-line=\"\"># (optional) Create a new Builder instance\ndocker buildx create --name mybuilder\n\n# (optional) Use created builder\ndocker buildx use mybuilder    \n\n# Show all available builder instances (here you can also see which CPU architectures are supported by the builder)\ndocker buildx ls\n\n# Build and push image for example for amd64, arm64 and arm\/v7\ndocker buildx build --platform linux\/amd64,linux\/arm64,linux\/arm\/v7 --tag username\/repository_name:tag_name --push .\n\n# Delete images\ndocker buildx prune --all\n<\/code><\/pre>\n<\/div>\n\n\n\n<figure class=\"wp-block-gallery columns-2 is-cropped wp-block-gallery-7 is-layout-flex wp-block-gallery-is-layout-flex\"><ul class=\"blocks-gallery-grid\"><li class=\"blocks-gallery-item\"><figure><a href=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/buildx1.png\"><img loading=\"lazy\" decoding=\"async\" width=\"908\" height=\"292\" data-attachment-id=\"21104\" data-permalink=\"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2021\/09\/11\/how-do-you-get-a-web-application-into-the-cloud\/buildx1\/\" data-orig-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/buildx1.png\" data-orig-size=\"908,292\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"buildx1\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/buildx1.png\" src=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/buildx1.png\" alt=\"\" data-id=\"21104\" data-full-url=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/buildx1.png\" data-link=\"https:\/\/blog.mi.hdm-stuttgart.de\/?attachment_id=21104\" class=\"wp-image-21104\" srcset=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/buildx1.png 908w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/buildx1-300x96.png 300w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/buildx1-768x247.png 768w\" sizes=\"auto, (max-width: 908px) 100vw, 908px\" \/><\/a><\/figure><\/li><li class=\"blocks-gallery-item\"><figure><a href=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/buildx2.png\"><img loading=\"lazy\" decoding=\"async\" width=\"468\" height=\"88\" data-attachment-id=\"21105\" data-permalink=\"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2021\/09\/11\/how-do-you-get-a-web-application-into-the-cloud\/buildx2\/\" data-orig-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/buildx2.png\" data-orig-size=\"468,88\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"buildx2\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/buildx2.png\" src=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/buildx2.png\" alt=\"\" data-id=\"21105\" data-full-url=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/buildx2.png\" data-link=\"https:\/\/blog.mi.hdm-stuttgart.de\/?attachment_id=21105\" class=\"wp-image-21105\" srcset=\"https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/buildx2.png 468w, https:\/\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2021\/09\/buildx2-300x56.png 300w\" sizes=\"auto, (max-width: 468px) 100vw, 468px\" \/><\/a><\/figure><\/li><\/ul><\/figure>\n","protected":false},"excerpt":{"rendered":"<p>by Dominik Ratzel (dr079) and Alischa Fritzsche (af094) For the lecture &#8220;Software Development for Cloud Computing&#8221;, we set ourselves the goal of exploring new things and gaining experience. We focused on one topic: &#8220;How do you get a web application into the cloud?&#8221;. In doing so, we took a closer look at Continuous Integration \/ [&hellip;]<\/p>\n","protected":false},"author":1052,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[120,650],"tags":[84,515,150,7,3,342,520,513,389,98,145,517,519,518,514,516],"ppma_author":[856],"class_list":["post-21064","post","type-post","status-publish","format-standard","hentry","category-cloud-technologies","category-scalable-systems","tag-aws","tag-buildx","tag-ci-cd","tag-cloud","tag-docker","tag-docker-compose","tag-docker-hub","tag-github","tag-github-actions","tag-gitlab","tag-gitlab-ci","tag-iaac","tag-lets-encrypt","tag-ssl","tag-terraform","tag-watchtower"],"aioseo_notices":[],"jetpack_featured_media_url":"","jetpack-related-posts":[{"id":7154,"url":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2019\/08\/31\/setting-up-a-ci-cd-pipeline-in-gitlab\/","url_meta":{"origin":21064,"position":0},"title":"Setting up a CI\/CD pipeline in Gitlab","author":"nr037","date":"31. August 2019","format":false,"excerpt":"Introduction For all my university software projects, I use the HdM Gitlab instance for version control. But Gitlab offers much more such as easy and good ways to operate a pipeline. In this article, I will show how we can use the CI\/CD functionality in a university project to perform\u2026","rel":"","context":"In &quot;Cloud Technologies&quot;","block_context":{"text":"Cloud Technologies","link":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/category\/scalable-systems\/cloud-technologies\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2019\/08\/Screenshot-2019-08-26-at-09.53.13.png?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2019\/08\/Screenshot-2019-08-26-at-09.53.13.png?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2019\/08\/Screenshot-2019-08-26-at-09.53.13.png?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2019\/08\/Screenshot-2019-08-26-at-09.53.13.png?resize=700%2C400&ssl=1 2x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2019\/08\/Screenshot-2019-08-26-at-09.53.13.png?resize=1050%2C600&ssl=1 3x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2019\/08\/Screenshot-2019-08-26-at-09.53.13.png?resize=1400%2C800&ssl=1 4x"},"classes":[]},{"id":10392,"url":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2020\/02\/29\/attempts-at-automating-the-build-process-of-a-net-wpf-application-with-gitlabs-ci-cd-pipeline\/","url_meta":{"origin":21064,"position":1},"title":"Attempts at automating the build process of a .NET WPF application with GitLab&#8217;s CI\/CD pipeline","author":"Felix Messner","date":"29. February 2020","format":false,"excerpt":"(Originally written for System Engineering and Management in 02\/2020) Introduction In the System Engineering course of WS1920, I took the opportunity to look into automating the build process of a Windows desktop application. Specifically, the application in question is built in C#, targeting .NET Framework 4.0 and using Windows Presentation\u2026","rel":"","context":"In &quot;Allgemein&quot;","block_context":{"text":"Allgemein","link":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/category\/allgemein\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2020\/08\/windows_runner_Tree.jpg?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2020\/08\/windows_runner_Tree.jpg?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2020\/08\/windows_runner_Tree.jpg?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2020\/08\/windows_runner_Tree.jpg?resize=700%2C400&ssl=1 2x"},"classes":[]},{"id":3314,"url":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2018\/03\/28\/continuous-integration-deployment-for-a-cross-platform-application-part-1\/","url_meta":{"origin":21064,"position":2},"title":"Continuous Integration &#038; Deployment for a Cross-Platform Application &#8211; Part 1","author":"Tobias Eberle, Marco Maisel, Tobias Staib, Mario Walz","date":"28. March 2018","format":false,"excerpt":"When we started the project \"Flora CI\" for the lecture \"System Engineering\", we planned to deal with Continuous Integration. As an important aspect of software engineering all of us have previously been involved in projects where code of developers had to be merged and builds had to be automated somehow.\u2026","rel":"","context":"In &quot;DevOps&quot;","block_context":{"text":"DevOps","link":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/category\/scalable-systems\/devops\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2018\/03\/flora-app.jpg?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2018\/03\/flora-app.jpg?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2018\/03\/flora-app.jpg?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2018\/03\/flora-app.jpg?resize=700%2C400&ssl=1 2x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2018\/03\/flora-app.jpg?resize=1050%2C600&ssl=1 3x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2018\/03\/flora-app.jpg?resize=1400%2C800&ssl=1 4x"},"classes":[]},{"id":26965,"url":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2025\/02\/28\/wie-baut-man-eine-ci-cd-pipeline-mit-jenkins-auf\/","url_meta":{"origin":21064,"position":3},"title":"Wie baut man eine CI\/CD Pipeline mit Jenkins auf?","author":"Cedric Gottschalk","date":"28. February 2025","format":false,"excerpt":"Im Rahmen der Vorlesung \"System Engineering und Management (143101a)\" haben wir es uns zum Ziel gesetzt, mehr \u00fcber CI\/CD Pipelines zu lernen und eine eigene Pipeline f\u00fcr ein kleines Projekt aufzusetzen. Wir haben uns dabei entschieden, Jenkins f\u00fcr die CI\/CD Pipeline einzusetzen und eine kleine ToDo App mit dem Framework\u2026","rel":"","context":"In &quot;System Engineering&quot;","block_context":{"text":"System Engineering","link":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/category\/system-designs\/system-engineering\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/02\/ToDo-List-CICD-1.png?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/02\/ToDo-List-CICD-1.png?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/02\/ToDo-List-CICD-1.png?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/02\/ToDo-List-CICD-1.png?resize=700%2C400&ssl=1 2x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/02\/ToDo-List-CICD-1.png?resize=1050%2C600&ssl=1 3x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2025\/02\/ToDo-List-CICD-1.png?resize=1400%2C800&ssl=1 4x"},"classes":[]},{"id":9816,"url":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2020\/02\/24\/using-gitlab-to-set-up-a-ci-cd-workflow-for-an-android-app-from-scratch\/","url_meta":{"origin":21064,"position":4},"title":"Using Gitlab to set up a CI\/CD workflow for an Android App from scratch","author":"Johannes Mauthe","date":"24. February 2020","format":false,"excerpt":"Tim Landenberger (tl061) Johannes Mauthe (jm130) Maximilian Narr (mn066) This blog post aims to provide an overview about how to setup a decent CI\/CD workflow for an android app with the capabilities of Gitlab. The blog post has been written for Gitlab Ultimate. Nevertheless, most features are also available in\u2026","rel":"","context":"In &quot;Allgemein&quot;","block_context":{"text":"Allgemein","link":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/category\/allgemein\/"},"img":{"alt_text":"","src":"https:\/\/lh3.googleusercontent.com\/TILM-T31y5pbvWRvoZbA53hR9mLaqMjANXKq7iGX_j-c19K_uiVnmKVDZV9DHBnGdPMgFogHmaNvLSy9gguK5rkMVLlosa4YuvYQQy-d090w90UjqUX_MbwizDt6_zQ1BlT6TrJ5","width":350,"height":200},"classes":[]},{"id":5313,"url":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/2019\/02\/26\/experiences-from-breaking-down-a-monolith-3\/","url_meta":{"origin":21064,"position":5},"title":"Experiences from breaking down a monolith (3)","author":"Marcel Heisler","date":"26. February 2019","format":false,"excerpt":"Written by Verena Barth, Marcel Heisler, Florian Rupp, & Tim Tenckhoff DevOps Code Sharing Building multiple services hold in separated code repositories, we headed the problem of code duplication. Multiple times a piece of code is used twice, for example data models. As the services grow larger, just copying is\u2026","rel":"","context":"In &quot;System Architecture&quot;","block_context":{"text":"System Architecture","link":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/category\/system-designs\/system-architecture\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2019\/02\/Bild_eingefugt_am_2019-02-26__1_31_PM-2-150x150.png?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2019\/02\/Bild_eingefugt_am_2019-02-26__1_31_PM-2-150x150.png?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2019\/02\/Bild_eingefugt_am_2019-02-26__1_31_PM-2-150x150.png?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/blog.mi.hdm-stuttgart.de\/wp-content\/uploads\/2019\/02\/Bild_eingefugt_am_2019-02-26__1_31_PM-2-150x150.png?resize=700%2C400&ssl=1 2x"},"classes":[]}],"jetpack_sharing_enabled":true,"authors":[{"term_id":856,"user_id":1052,"is_guest":0,"slug":"af094","display_name":"af094","avatar_url":"https:\/\/secure.gravatar.com\/avatar\/669be3af075537ae838419c0cb92445ae36f62fea3724b8d126efd2d06ae190f?s=96&d=mm&r=g","0":null,"1":"","2":"","3":"","4":"","5":"","6":"","7":"","8":""}],"_links":{"self":[{"href":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/wp-json\/wp\/v2\/posts\/21064","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/wp-json\/wp\/v2\/users\/1052"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/wp-json\/wp\/v2\/comments?post=21064"}],"version-history":[{"count":33,"href":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/wp-json\/wp\/v2\/posts\/21064\/revisions"}],"predecessor-version":[{"id":21119,"href":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/wp-json\/wp\/v2\/posts\/21064\/revisions\/21119"}],"wp:attachment":[{"href":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/wp-json\/wp\/v2\/media?parent=21064"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/wp-json\/wp\/v2\/categories?post=21064"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/wp-json\/wp\/v2\/tags?post=21064"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/blog.mi.hdm-stuttgart.de\/index.php\/wp-json\/wp\/v2\/ppma_author?post=21064"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}