{"id":15218,"date":"2016-11-14T12:15:21","date_gmt":"2016-11-14T10:15:21","guid":{"rendered":"https:\/\/www.webcodegeeks.com\/?p=15218"},"modified":"2016-11-11T11:38:20","modified_gmt":"2016-11-11T09:38:20","slug":"turning-app-separate-containers-better-cicd","status":"publish","type":"post","link":"https:\/\/www.webcodegeeks.com\/devops\/turning-app-separate-containers-better-cicd\/","title":{"rendered":"Turning Your App into Separate Containers for Better CI\/CD"},"content":{"rendered":"<p>Guess how long the test and build process is for my most recent project? Twenty minutes. I\u2019m not kidding.<\/p>\n<p>It takes over 10 minutes to run my build process and another 10 to run my several thousand unit tests. Tack onto that dozens of code pushes a day, and waiting for a passing test suite means a lot of wasted time. Unfortunately for me, this time suck can only get worse because I\u2019m not exactly about to start deleting unit tests.<\/p>\n<p>So, what is a software developer to do?<\/p>\n<p>Well, the obvious answer is to optimize my unit tests and build process, but let\u2019s pretend for a minute that everything is fully optimized already. How can I make my CI\/CD process better if I\u2019m out of direct optimizations? Let\u2019s start from the beginning. In this post, you will learn how to optimize your CI\/CD process with Codeship\u2019s Docker-based infrastructure to speed up your tests.<\/p>\n<h2>Getting Started<\/h2>\n<p>To get going, let\u2019s take a look at an established open-source project with an existing build process and decent number of unit tests.<\/p>\n<p>The <a href=\"https:\/\/laravel.com\/\">Laravel Framework<\/a> fits the bill quite nicely. It has a large test suite and build process, which will allow me to not only demonstrate the existing build speed but also compare it to an optimized build speed. Because we\u2019re only benchmarking the difference between serialized and parallelized test and build processes (and not actually contributing to this project), I\u2019ve branched off of the Laravel\u2019s master branch into one specifically for this demonstration (called <a href=\"https:\/\/github.com\/codeship\/framework\/tree\/codeship-jet-parallel-ci\">codeship-jetparallel-ci<\/a>).<\/p>\n<h2>Dockerfile<\/h2>\n<p>Okay, now that we have a codebase and a Codeship-specific branch, we need to prepare it to run our tests using Docker and Codeship. (I\u2019m not going to cover getting Docker and the Jet CLI tool installed, so I suggest you follow Codeship\u2019s own <a href=\"https:\/\/documentation.codeship.com\/docker-guide\/getting-started\/\">Jet installation tutorial<\/a> before moving forward.)<\/p>\n<p>The first thing we need to do is set up a Dockerfile. If you are new to Docker, this file is used to configure a container that is managed by Docker.<\/p>\n<pre class=\"brush:php\"># Start with the offical image for PHP 5.6\r\nFROM php:5.6\r\n\r\n# Install additonal packages\r\nRUN apt-get update\r\nRUN apt-get install -y git unzip libmcrypt-dev libmemcached-dev libz-dev\r\nRUN pecl install memcached\r\n\r\n# Install\/Enable PHP extensions\r\nRUN docker-php-ext-install pcntl mcrypt\r\nRUN echo extension=memcached.so &gt;&gt; \/usr\/local\/etc\/php\/conf.d\/memcached.ini\r\n\r\n# Install Composer and make it available in the PATH\r\nRUN curl -sS https:\/\/getcomposer.org\/installer | php -- --install-dir=\/usr\/bin\/ --filename=composer\r\n\r\n# Set the current working directory\r\nWORKDIR \/app\r\n\r\n# Copy the source code onto the container (required by composer)\r\nCOPY src .\/src\r\n\r\n# Copy over the composer.json and run composer install.\r\n# This is done as a separate steps so the image can be cached this step won't be\r\n# rerun unless you change composer.json\r\nCOPY composer.json .\/\r\nRUN composer install --prefer-source --no-interaction\r\n\r\n# Finally copy the tests onto the container\r\nCOPY phpunit.xml .\/\r\nCOPY tests .\/tests<\/pre>\n<h2>Services and Steps<\/h2>\n<p>Now, with our Dockerfile, we are able to spin up a suitable Docker container for building and testing our codebase. However, the Dockerfile is only part of the solution. We also need to tell Codeship about our Dockerfile, as well as which steps to take in order to run our test suite. This is accomplished using two files: <a href=\"https:\/\/documentation.codeship.com\/docker\/services\/\">codeship_services.yml<\/a> and <a href=\"https:\/\/documentation.codeship.com\/docker\/steps\/\">codeship_steps.yml<\/a>.<\/p>\n<p>The codeship-services.yml file is essentially a Docker Compose file, which defines any services, networks, and volumes our build process might need. To get started, we\u2019ll keep our services file pretty lightweight by only building one image. It is important to note here that Codeship supports a <a href=\"https:\/\/documentation.codeship.com\/docker\/caching\/\">\u2018cached\u2019 directive<\/a> that attempts to reuse previous builds in order to speed up the build process.<\/p>\n<pre class=\"brush:php\">app:\r\n  build:\r\n    image: app\r\n    dockerfile_path: Dockerfile\r\n  cached: true<\/pre>\n<p>Next, the <code>codeship-steps.yml<\/code> file is a configuration file that defines the steps of the build, test, and deploy process. Again, to get started, we\u2019re going to keep this file lightweight. For now, we\u2019ll run our entire test suite all at once. Also, while we are only running one step at first, I have directed Codeship and Jet to run my steps in parallel. This will come in handy in a little bit.<\/p>\n<pre class=\"brush:php\">- type: parallel\r\n  steps:\r\n  - service: app\r\n    command: vendor\/bin\/phpunit<\/pre>\n<h2>Putting It All Together<\/h2>\n<p>Now that we have our three configuration settings (and hopefully have Jet and Docker configured locally), we\u2019re ready to put it all together! To run our test process, simply call the <code>jet steps<\/code> command from within the project directory. Here\u2019s a quick screenshot of the results of the first run process:<\/p>\n<p><a href=\"http:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2016\/11\/image01.png\"><img decoding=\"async\" class=\"aligncenter wp-image-15220\" src=\"http:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2016\/11\/image01.png\" alt=\"image01\" width=\"860\" height=\"553\" srcset=\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2016\/11\/image01.png 930w, https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2016\/11\/image01-300x193.png 300w, https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2016\/11\/image01-768x494.png 768w\" sizes=\"(max-width: 860px) 100vw, 860px\" \/><\/a><\/p>\n<p>As you can see, excluding the build time (which I precached to speed subsequent tests up), the entire test suite of this project takes about 20 seconds. Not a bad base benchmark, but we can do better.<\/p>\n<h2>Parallelization<\/h2>\n<p>So, how do we fix the long build time? This is where the <a href=\"https:\/\/documentation.codeship.com\/docker\/steps\/#group-steps\">\u2018parallel\u2019 directive<\/a> from the <code>codeship-steps.yml<\/code> file comes into play.<\/p>\n<p>What this directive does is allow us to run steps in parallel, which in this case means running each subdirectory in our tests directory independently of the others. We can therefore run multiple tests at once, which will in turn let us drastically reduce the length of our test time. This is achieved by spinning up separate containers, in order to allow us to retain control over performance and resource use.<\/p>\n<pre class=\"brush:php\">- type: parallel\r\n  steps:\r\n  - service: app\r\n    command: vendor\/bin\/phpunit tests\/Auth\/\r\n  - service: app\r\n    command: vendor\/bin\/phpunit tests\/Broadcasting\/\r\n  - service: app\r\n    command: vendor\/bin\/phpunit tests\/Bus\/\r\n  - service: app\r\n    command: vendor\/bin\/phpunit tests\/Cache\/\r\n  - service: app\r\n    command: vendor\/bin\/phpunit tests\/Console\/\r\n  - service: app\r\n    command: vendor\/bin\/phpunit tests\/Container\/\r\n  - service: app\r\n    command: vendor\/bin\/phpunit tests\/Cookie\/\r\n  - service: app\r\n    command: vendor\/bin\/phpunit tests\/Database\/\r\n  - service: app\r\n    command: vendor\/bin\/phpunit tests\/Encryption\/\r\n  - service: app\r\n    command: vendor\/bin\/phpunit tests\/Events\/\r\n  - service: app\r\n    command: vendor\/bin\/phpunit tests\/Filesystem\/\r\n  - service: app\r\n    command: vendor\/bin\/phpunit tests\/Foundation\/\r\n  - service: app\r\n    command: vendor\/bin\/phpunit tests\/Hashing\/\r\n  - service: app\r\n    command: vendor\/bin\/phpunit tests\/Http\/\r\n  - service: app\r\n    command: vendor\/bin\/phpunit tests\/Log\/\r\n  - service: app\r\n    command: vendor\/bin\/phpunit tests\/Mail\/\r\n  - service: app\r\n    command: vendor\/bin\/phpunit tests\/Pagination\/\r\n  - service: app\r\n    command: vendor\/bin\/phpunit tests\/Pipeline\/\r\n  - service: app\r\n    command: vendor\/bin\/phpunit tests\/Queue\/\r\n  - service: app\r\n    command: vendor\/bin\/phpunit tests\/Redis\/\r\n  - service: app\r\n    command: vendor\/bin\/phpunit tests\/Routing\/\r\n  - service: app\r\n    command: vendor\/bin\/phpunit tests\/Session\/\r\n  - service: app\r\n    command: vendor\/bin\/phpunit tests\/Support\/\r\n  - service: app\r\n    command: vendor\/bin\/phpunit tests\/Translation\/\r\n  - service: app\r\n    command: vendor\/bin\/phpunit tests\/Validation\/\r\n  - service: app\r\n    command: vendor\/bin\/phpunit tests\/View\/<\/pre>\n<p>With just a little tweak to our <code>codeship-steps.yml<\/code> file, we can split up our test suite into multiple parallel processes, which reduces our total test time to 14 seconds. In a test suite that takes less than a minute, the speedup might feel negligible, but in a large suite with 10 minutes\u2019 worth of tests, this can save us a ton of time in the long run.<\/p>\n<p><a href=\"http:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2016\/11\/image02.png\"><img decoding=\"async\" class=\"aligncenter wp-image-15221\" src=\"http:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2016\/11\/image02.png\" alt=\"image02\" width=\"860\" height=\"553\" srcset=\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2016\/11\/image02.png 930w, https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2016\/11\/image02-300x193.png 300w, https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2016\/11\/image02-768x494.png 768w\" sizes=\"(max-width: 860px) 100vw, 860px\" \/><\/a><\/p>\n<h2>Multiple Services<\/h2>\n<p>Up to this point, we\u2019ve been focusing on speeding up our test suite through parallelization, but what about the rest of the process? How can we optimize everything from building to deploying? This is where the <code>codeshipservices.yml<\/code> file comes into play.<\/p>\n<p>The syntax of this file is based on <a href=\"https:\/\/docs.docker.com\/compose\/overview\/\">Docker Compose<\/a> (meaning <a href=\"https:\/\/documentation.codeship.com\/docker\/services\/#unavailable-features\">most<\/a> syntax supported by Docker Compose is supported by Codeship Services), which is used to define multiple Docker containers for use in our build process. With a few small changes to this file, we can persist data across our containers, which will allow us to reduce unnecessary overhead and streamline each step.<\/p>\n<h2>Build and Test<\/h2>\n<p>To accomplish this, the first thing we need to do is split our build and test steps into two separate services. To keep this example straightforward, we will be using the same Dockerfile; however in the event that different processes require different packages, using multiple Dockerfiles would be appropriate.<\/p>\n<pre class=\"brush:php\">build:\r\n  build:\r\n    image: app\r\n    dockerfile_path: Dockerfile\r\n  cached: true\r\n  volumes_from:\r\n    - data\r\ntest:\r\n  build:\r\n    image: app\r\n    dockerfile_path: Dockerfile\r\n  cached: true\r\n  volumes_from:\r\n    - data\r\ndata:\r\n  image: busybox\r\n  volumes:\r\n    - .\/vendor:\/app\/vendor<\/pre>\n<p>Let\u2019s break this file down a bit.<\/p>\n<p>As you can see, the original app service has been duplicated into two separate services: build and test. What\u2019s different about these two services \u2014 <a href=\"https:\/\/documentation.codeship.com\/docker\/services\/#volumes\">the <code>volumes<\/code><\/a> and <code>volumes_from<\/code> directives. Because each service will require a fully built application, the test service inherits mounted volumes from the build service. What this means is that when the build process is run (via Composer), the resulting packages are persisted across each container.<\/p>\n<p>I should note that because this is a backend PHP framework we are working with, the build process is a fairly simple installation of third-party PHP packages. In more complicated codebases, however, the build step could include anything from binary compilation to asset uglification and minification (the sky\u2019s really the limit here). This flexibility is advantageous from a DevOps perspective because it assures that you are free to use whichever frameworks and development tools are the best fit \u2014 which is one of the key reasons for using Docker and a microservices architecture in the first place.<\/p>\n<h2>Deploy<\/h2>\n<p>Up until now, we have been doing all of our work locally via the Jet CLI tool, but at some point we need to actually start pushing data somewhere. Thankfully, Codeship supports <a href=\"https:\/\/documentation.codeship.com\/docker\/docker-push\/\">deploying containers to remote registries<\/a>, which allows us to deploy a built container wherever we want. While deployments are pretty par for the course when it comes to CI\/CD services, what makes this unique is our ability to control exactly what gets deployed, and when.<\/p>\n<p>For example, we might want to push our container to the remote registry before updating a code coverage report, or run database migrations in a parallel process. Or maybe we don\u2019t want to deploy to a container image at all. Deployments could also be artifacts, APIs, or even to SFTP. This is a major advantage, since it means you can deploy to whatever infrastructure you already have. You don\u2019t have to change your infrastructure to match your new development workflow.<\/p>\n<p>Here, though, I\u2019ll cover the basics of deploying to a container registry. I won\u2019t go over the remote registry pushing configuration process because <a href=\"https:\/\/documentation.codeship.com\/docker\/docker-push\/\">Codeship explains it<\/a> much more effectively than I would, but in the context of this demo, it\u2019s as simple as adding an additional step to our <a href=\"https:\/\/documentation.codeship.com\/docker\/docker-push\/\">codeship-steps.yml<\/a> file.<\/p>\n<pre class=\"brush:php\">- type: serial\r\n  steps:\r\n    - type: serial\r\n      steps:\r\n        - service: build\r\n          command: composer install --prefer-source --no-interaction\r\n    - type: parallel\r\n      steps:\r\n        - service: test\r\n          command: vendor\/bin\/phpunit tests\/Auth\/\r\n        - service: test\r\n          command: vendor\/bin\/phpunit tests\/Broadcasting\/\r\n        - service: test\r\n          command: vendor\/bin\/phpunit tests\/Bus\/\r\n        - service: test\r\n          command: vendor\/bin\/phpunit tests\/Cache\/\r\n        - service: test\r\n          command: vendor\/bin\/phpunit tests\/Console\/\r\n        - service: test\r\n          command: vendor\/bin\/phpunit tests\/Container\/\r\n        - service: test\r\n          command: vendor\/bin\/phpunit tests\/Cookie\/\r\n        - service: test\r\n          command: vendor\/bin\/phpunit tests\/Database\/\r\n        - service: test\r\n          command: vendor\/bin\/phpunit tests\/Encryption\/\r\n        - service: test\r\n          command: vendor\/bin\/phpunit tests\/Events\/\r\n        - service: test\r\n          command: vendor\/bin\/phpunit tests\/Filesystem\/\r\n        - service: test\r\n          command: vendor\/bin\/phpunit tests\/Foundation\/\r\n        - service: test\r\n          command: vendor\/bin\/phpunit tests\/Hashing\/\r\n        - service: test\r\n          command: vendor\/bin\/phpunit tests\/Http\/\r\n        - service: test\r\n          command: vendor\/bin\/phpunit tests\/Log\/\r\n        - service: test\r\n          command: vendor\/bin\/phpunit tests\/Mail\/\r\n        - service: test\r\n          command: vendor\/bin\/phpunit tests\/Pagination\/\r\n        - service: test\r\n          command: vendor\/bin\/phpunit tests\/Pipeline\/\r\n        - service: test\r\n          command: vendor\/bin\/phpunit tests\/Queue\/\r\n        - service: test\r\n          command: vendor\/bin\/phpunit tests\/Redis\/\r\n        - service: test\r\n          command: vendor\/bin\/phpunit tests\/Routing\/\r\n        - service: test\r\n          command: vendor\/bin\/phpunit tests\/Session\/\r\n        - service: test\r\n          command: vendor\/bin\/phpunit tests\/Support\/\r\n        - service: test\r\n          command: vendor\/bin\/phpunit tests\/Translation\/\r\n        - service: test\r\n          command: vendor\/bin\/phpunit tests\/Validation\/\r\n        - service: test\r\n          command: vendor\/bin\/phpunit tests\/View\/\r\n    - type: serial\r\n      steps:\r\n        - service: build\r\n          type: push\r\n          image_name: zachflower\/codeship-jet-parallel-ci\r\n          registry: https:\/\/index.docker.io\/v1\/\r\n          encrypted_dockercfg_path: dockercfg.encrypted<\/pre>\n<p>If you followed the Codeship documentation for enabling repository pushes, then you can see that getting it hooked into this demo was surprisingly easy. One quick push to GitHub later, and we now have an end-to-end build, test, and deploy process split across multiple containers and steps!<\/p>\n<p><a href=\"http:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2016\/11\/image00.png\"><img decoding=\"async\" class=\"aligncenter wp-image-15222\" src=\"http:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2016\/11\/image00.png\" alt=\"image00\" width=\"860\" height=\"459\" srcset=\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2016\/11\/image00.png 1393w, https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2016\/11\/image00-300x160.png 300w, https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2016\/11\/image00-768x410.png 768w, https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2016\/11\/image00-1024x546.png 1024w, https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2016\/11\/image00-620x330.png 620w\" sizes=\"(max-width: 860px) 100vw, 860px\" \/><\/a><\/p>\n<h2>Conclusion<\/h2>\n<p>While this is a very limited demo, the potential here should be self-evident. The power of Codeship\u2019s Docker support is incredible, and with the addition of their <a href=\"https:\/\/documentation.codeship.com\/docker\/installation\/\">Jet CLI tool<\/a>, you can incorporate it into your development process right from the start.<\/p>\n<div class=\"attribution\">\n<table>\n<tbody>\n<tr>\n<td><span class=\"reference\">Reference: <\/span><\/td>\n<td><a href=\"https:\/\/blog.codeship.com\/turning-your-app-into-separate-containers-for-better-cicd\/\">Turning Your App into Separate Containers for Better CI\/CD<\/a> from our <a href=\"http:\/\/www.webcodegeeks.com\/join-us\/wcg\/\">WCG partner<\/a> Zachary Flower at the <a href=\"http:\/\/blog.codeship.com\/\">Codeship Blog<\/a> blog.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Guess how long the test and build process is for my most recent project? Twenty minutes. I\u2019m not kidding. It takes over 10 minutes to run my build process and another 10 to run my several thousand unit tests. Tack onto that dozens of code pushes a day, and waiting for a passing test suite &hellip;<\/p>\n","protected":false},"author":200,"featured_media":10356,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[17],"tags":[217],"class_list":["post-15218","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-devops","tag-docker"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v26.5 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Turning Your App into Separate Containers for Better CI\/CD - Web Code Geeks - 2026<\/title>\n<meta name=\"description\" content=\"Guess how long the test and build process is for my most recent project? Twenty minutes. I\u2019m not kidding. It takes over 10 minutes to run my build process\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.webcodegeeks.com\/devops\/turning-app-separate-containers-better-cicd\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Turning Your App into Separate Containers for Better CI\/CD - Web Code Geeks - 2026\" \/>\n<meta property=\"og:description\" content=\"Guess how long the test and build process is for my most recent project? Twenty minutes. I\u2019m not kidding. It takes over 10 minutes to run my build process\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.webcodegeeks.com\/devops\/turning-app-separate-containers-better-cicd\/\" \/>\n<meta property=\"og:site_name\" content=\"Web Code Geeks\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/webcodegeeks\" \/>\n<meta property=\"article:published_time\" content=\"2016-11-14T10:15:21+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2016\/01\/docker-logo.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"150\" \/>\n\t<meta property=\"og:image:height\" content=\"150\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Zachary Flower\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@webcodegeeks\" \/>\n<meta name=\"twitter:site\" content=\"@webcodegeeks\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Zachary Flower\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"11 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.webcodegeeks.com\/devops\/turning-app-separate-containers-better-cicd\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/devops\/turning-app-separate-containers-better-cicd\/\"},\"author\":{\"name\":\"Zachary Flower\",\"@id\":\"https:\/\/www.webcodegeeks.com\/#\/schema\/person\/fad2572903e5f01809fc0ebd87f660cf\"},\"headline\":\"Turning Your App into Separate Containers for Better CI\/CD\",\"datePublished\":\"2016-11-14T10:15:21+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/devops\/turning-app-separate-containers-better-cicd\/\"},\"wordCount\":1471,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/devops\/turning-app-separate-containers-better-cicd\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2016\/01\/docker-logo.jpg\",\"keywords\":[\"Docker\"],\"articleSection\":[\"DevOps\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.webcodegeeks.com\/devops\/turning-app-separate-containers-better-cicd\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.webcodegeeks.com\/devops\/turning-app-separate-containers-better-cicd\/\",\"url\":\"https:\/\/www.webcodegeeks.com\/devops\/turning-app-separate-containers-better-cicd\/\",\"name\":\"Turning Your App into Separate Containers for Better CI\/CD - Web Code Geeks - 2026\",\"isPartOf\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/devops\/turning-app-separate-containers-better-cicd\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/devops\/turning-app-separate-containers-better-cicd\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2016\/01\/docker-logo.jpg\",\"datePublished\":\"2016-11-14T10:15:21+00:00\",\"description\":\"Guess how long the test and build process is for my most recent project? Twenty minutes. I\u2019m not kidding. It takes over 10 minutes to run my build process\",\"breadcrumb\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/devops\/turning-app-separate-containers-better-cicd\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.webcodegeeks.com\/devops\/turning-app-separate-containers-better-cicd\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.webcodegeeks.com\/devops\/turning-app-separate-containers-better-cicd\/#primaryimage\",\"url\":\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2016\/01\/docker-logo.jpg\",\"contentUrl\":\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2016\/01\/docker-logo.jpg\",\"width\":150,\"height\":150},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.webcodegeeks.com\/devops\/turning-app-separate-containers-better-cicd\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.webcodegeeks.com\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"DevOps\",\"item\":\"https:\/\/www.webcodegeeks.com\/category\/devops\/\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Turning Your App into Separate Containers for Better CI\/CD\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.webcodegeeks.com\/#website\",\"url\":\"https:\/\/www.webcodegeeks.com\/\",\"name\":\"Web Code Geeks\",\"description\":\"Web Developers Resource Center\",\"publisher\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.webcodegeeks.com\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.webcodegeeks.com\/#organization\",\"name\":\"Exelixis Media P.C.\",\"url\":\"https:\/\/www.webcodegeeks.com\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.webcodegeeks.com\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png\",\"contentUrl\":\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png\",\"width\":864,\"height\":246,\"caption\":\"Exelixis Media P.C.\"},\"image\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/www.facebook.com\/webcodegeeks\",\"https:\/\/x.com\/webcodegeeks\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.webcodegeeks.com\/#\/schema\/person\/fad2572903e5f01809fc0ebd87f660cf\",\"name\":\"Zachary Flower\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.webcodegeeks.com\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/cf21b18b45a53a55fbc1de5e222fe603b2602ee381f36abf004a8d6c81ffa1ed?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/cf21b18b45a53a55fbc1de5e222fe603b2602ee381f36abf004a8d6c81ffa1ed?s=96&d=mm&r=g\",\"caption\":\"Zachary Flower\"},\"description\":\"Zachary Flower is a freelance web developer, writer, and polymath. He's built projects for the NSA and created features for companies like Name.com and Buffer.\",\"url\":\"https:\/\/www.webcodegeeks.com\/author\/zachary-flower\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Turning Your App into Separate Containers for Better CI\/CD - Web Code Geeks - 2026","description":"Guess how long the test and build process is for my most recent project? Twenty minutes. I\u2019m not kidding. It takes over 10 minutes to run my build process","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.webcodegeeks.com\/devops\/turning-app-separate-containers-better-cicd\/","og_locale":"en_US","og_type":"article","og_title":"Turning Your App into Separate Containers for Better CI\/CD - Web Code Geeks - 2026","og_description":"Guess how long the test and build process is for my most recent project? Twenty minutes. I\u2019m not kidding. It takes over 10 minutes to run my build process","og_url":"https:\/\/www.webcodegeeks.com\/devops\/turning-app-separate-containers-better-cicd\/","og_site_name":"Web Code Geeks","article_publisher":"https:\/\/www.facebook.com\/webcodegeeks","article_published_time":"2016-11-14T10:15:21+00:00","og_image":[{"width":150,"height":150,"url":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2016\/01\/docker-logo.jpg","type":"image\/jpeg"}],"author":"Zachary Flower","twitter_card":"summary_large_image","twitter_creator":"@webcodegeeks","twitter_site":"@webcodegeeks","twitter_misc":{"Written by":"Zachary Flower","Est. reading time":"11 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.webcodegeeks.com\/devops\/turning-app-separate-containers-better-cicd\/#article","isPartOf":{"@id":"https:\/\/www.webcodegeeks.com\/devops\/turning-app-separate-containers-better-cicd\/"},"author":{"name":"Zachary Flower","@id":"https:\/\/www.webcodegeeks.com\/#\/schema\/person\/fad2572903e5f01809fc0ebd87f660cf"},"headline":"Turning Your App into Separate Containers for Better CI\/CD","datePublished":"2016-11-14T10:15:21+00:00","mainEntityOfPage":{"@id":"https:\/\/www.webcodegeeks.com\/devops\/turning-app-separate-containers-better-cicd\/"},"wordCount":1471,"commentCount":0,"publisher":{"@id":"https:\/\/www.webcodegeeks.com\/#organization"},"image":{"@id":"https:\/\/www.webcodegeeks.com\/devops\/turning-app-separate-containers-better-cicd\/#primaryimage"},"thumbnailUrl":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2016\/01\/docker-logo.jpg","keywords":["Docker"],"articleSection":["DevOps"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.webcodegeeks.com\/devops\/turning-app-separate-containers-better-cicd\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.webcodegeeks.com\/devops\/turning-app-separate-containers-better-cicd\/","url":"https:\/\/www.webcodegeeks.com\/devops\/turning-app-separate-containers-better-cicd\/","name":"Turning Your App into Separate Containers for Better CI\/CD - Web Code Geeks - 2026","isPartOf":{"@id":"https:\/\/www.webcodegeeks.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.webcodegeeks.com\/devops\/turning-app-separate-containers-better-cicd\/#primaryimage"},"image":{"@id":"https:\/\/www.webcodegeeks.com\/devops\/turning-app-separate-containers-better-cicd\/#primaryimage"},"thumbnailUrl":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2016\/01\/docker-logo.jpg","datePublished":"2016-11-14T10:15:21+00:00","description":"Guess how long the test and build process is for my most recent project? Twenty minutes. I\u2019m not kidding. It takes over 10 minutes to run my build process","breadcrumb":{"@id":"https:\/\/www.webcodegeeks.com\/devops\/turning-app-separate-containers-better-cicd\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.webcodegeeks.com\/devops\/turning-app-separate-containers-better-cicd\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.webcodegeeks.com\/devops\/turning-app-separate-containers-better-cicd\/#primaryimage","url":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2016\/01\/docker-logo.jpg","contentUrl":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2016\/01\/docker-logo.jpg","width":150,"height":150},{"@type":"BreadcrumbList","@id":"https:\/\/www.webcodegeeks.com\/devops\/turning-app-separate-containers-better-cicd\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.webcodegeeks.com\/"},{"@type":"ListItem","position":2,"name":"DevOps","item":"https:\/\/www.webcodegeeks.com\/category\/devops\/"},{"@type":"ListItem","position":3,"name":"Turning Your App into Separate Containers for Better CI\/CD"}]},{"@type":"WebSite","@id":"https:\/\/www.webcodegeeks.com\/#website","url":"https:\/\/www.webcodegeeks.com\/","name":"Web Code Geeks","description":"Web Developers Resource Center","publisher":{"@id":"https:\/\/www.webcodegeeks.com\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.webcodegeeks.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.webcodegeeks.com\/#organization","name":"Exelixis Media P.C.","url":"https:\/\/www.webcodegeeks.com\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.webcodegeeks.com\/#\/schema\/logo\/image\/","url":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png","contentUrl":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png","width":864,"height":246,"caption":"Exelixis Media P.C."},"image":{"@id":"https:\/\/www.webcodegeeks.com\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/webcodegeeks","https:\/\/x.com\/webcodegeeks"]},{"@type":"Person","@id":"https:\/\/www.webcodegeeks.com\/#\/schema\/person\/fad2572903e5f01809fc0ebd87f660cf","name":"Zachary Flower","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.webcodegeeks.com\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/cf21b18b45a53a55fbc1de5e222fe603b2602ee381f36abf004a8d6c81ffa1ed?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/cf21b18b45a53a55fbc1de5e222fe603b2602ee381f36abf004a8d6c81ffa1ed?s=96&d=mm&r=g","caption":"Zachary Flower"},"description":"Zachary Flower is a freelance web developer, writer, and polymath. He's built projects for the NSA and created features for companies like Name.com and Buffer.","url":"https:\/\/www.webcodegeeks.com\/author\/zachary-flower\/"}]}},"_links":{"self":[{"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/posts\/15218","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/users\/200"}],"replies":[{"embeddable":true,"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/comments?post=15218"}],"version-history":[{"count":0,"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/posts\/15218\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/media\/10356"}],"wp:attachment":[{"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/media?parent=15218"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/categories?post=15218"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/tags?post=15218"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}