<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Lessons from Blue Ocean Docker]]></title><description><![CDATA[Learn how to use Docker to its fullest potential with the latest lessons from  Blue Ocean Docker]]></description><link>https://www.blueoceandocker.com</link><generator>Blue Ocean Docker</generator><lastBuildDate>Fri, 23 May 2025 02:29:44 GMT</lastBuildDate><atom:link href="https://www.blueoceandocker.com/feed.xml" rel="self" type="application/rss+xml"/><pubDate>Sun, 20 Aug 2023 06:00:00 GMT</pubDate><copyright><![CDATA[2025]]></copyright><language><![CDATA[en]]></language><managingEditor><![CDATA[TJ Draper]]></managingEditor><webMaster><![CDATA[TJ Draper]]></webMaster><item><title><![CDATA[Lesson 3: Running a Container]]></title><description><![CDATA[Learn how to set up and run a Docker container<br><br><iframe width="560" height="315" src="https://www.youtube.com/embed/IuQXVzaQyoI" title="Lesson 3: Running a Container" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe><br><br>If you prefer to read the lesson, rather than watch the video, I’ve got you covered!<h3>Lesson article:</h3><hr /><h1>Running a Container</h1>
<p>Now that we’ve learned the basics, we’re going to dive in to some specifics. In this lesson, we’ll learn how to run a container. What we’ll be doing is executing commands in containers running on your computer. The containers will start up and run, and then shut down.</p>
<p>In future lessons we’ll talk about starting and running an entire environment of containers, keeping them online, running in production, etc. But for now, we’re just going to focus on running commands.</p>
<p>The first thing to note is that <a href="https://hub.docker.com/">hub.docker.com</a> is where you go to find public images. For instance, if you want a PHP image, you can go <a href="https://hub.docker.com/_/php">here to the official PHP image</a>.</p>
<p>And you can note on the <a href="https://hub.docker.com/_/php/tags">tags tab</a> that there are many different tags for the PHP image.</p>
<p><img src="/lesson/running-a-container/docker-hub-php.jpg" alt="Docker Hub PHP Image Tags"></p>
<p>With Docker images, tags are different versions of an image. Tags are deleniated by a colon. For instance, <code>php:8.4.7</code> where <code>8.4.7</code> is a tag that is available.</p>
<div class="markdown-alert markdown-alert-note"><p class="markdown-alert-title"><svg class="octicon octicon-info mr-2" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path></svg>Note</p><p>For pretty much every image, you’ll see a tag called “latest”. That is a convention in the Docker world that the most recent image is always tagged “latest.” So for instance, if you did <code>docker pull php:latest</code>, you would get the most recent version of the vanilla PHP image.</p>
</div>
<p>With most images, tags are used as a type of version control method. For instance, if you have an older application that can’t yet run PHP 8, you can run PHP 7 by specifying one of the <code>7</code> tags.</p>
<h2>The <code>docker run</code> command</h2>
<p>So let’s get started running an image. To do that, you’ll use the <code>docker run</code> command with some arguments.</p>
<p>Here’s the command you’ll run: <code>docker run -it php bash</code>. Let’s break that command down. <code>-i</code> is the flag for “interactive” and <code>-t</code> is the flag for teletype. So those two flags are telling the Docker container that you want an interactive session with the container.</p>
<p>The first argument after <code>run</code> — in this case, <code>php</code> — is telling the <code>run</code> command which image you want to run. If you do not specify a tag with a colon (something like <code>php:7.2</code>) then it will default to <code>:latest</code>.</p>
<p>The second argument after the <code>run</code> command is what the container should execute. In this case, we want to run <code>bash</code>. Not all images may have <code>bash</code>, but PHP does, so we’ll run bash here in our interactive session.</p>
<p>So go ahead and run the command:</p>
<pre><code class="language-bash">docker run -it php bash
</code></pre>
<p>Notice if you’ve never run or pulled the image before that it will download the image.</p>
<p><img src="/lesson/running-a-container/docker-run-download-image.jpg" alt="Docker Run Download Image"></p>
<p>After the image downloads (if needed), you should be in a bash session inside a running PHP container. For instance, if you run <code>ls -lah</code> in that session, you can see all the stuff in the root of the container that you’re in.</p>
<p><img src="/lesson/running-a-container/docker-run-ls.jpg" alt="docker-run-ls.jpg"></p>
<h2>The <code>docker ps</code> and <code>docker rm</code> commands</h2>
<p>Now if you <code>exit</code> the container, the container will stop running. But here’s something important to take note of: we didn’t specify what to do when the container stopped running. So the container, or the ghost of the container, is actually still sitting around, stopped, not running, but there.</p>
<p>You can confirm this by running <code>docker ps -a</code>. <code>ps</code> lists containers, and the <code>-a</code> flag tells the command to list all containers, including the stopped containers.</p>
<div class="markdown-alert markdown-alert-note"><p class="markdown-alert-title"><svg class="octicon octicon-info mr-2" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path></svg>Note</p><p>By default, <code>docker ps</code> will only list running containers. Use the <code>-a</code> flag to list even stopped containers that still exist.</p>
</div>
<p>Go ahead and run this command now:</p>
<pre><code class="language-bash">docker ps -a
</code></pre>
<p><img src="/lesson/running-a-container/docker-ps-a.jpg" alt="docker ps -a"></p>
<p>It should list the container you just ran with a status of <code>Exited</code>, which means it’s no longer running.</p>
<p>If you’re using <a href="https://docs.docker.com/desktop/">Docker Desktop</a> (or <a href="https://orbstack.dev/">OrbStack</a>), you can also see in the GUI interface the status of containers, including containers that have exited and are no longer running, and you can delete them from there.</p>
<p><img src="/lesson/running-a-container/docker-desktop-exited-container.jpg" alt="Docker Desktop Exited Containers"></p>
<p>You can also use the <code>docker rm</code> command, sending it the ID of the container to <code>rm</code> as the first argument. The argument doesn’t have to be the full ID, but requires enough of the ID to be unique. Usually just the first three characters of the ID are enough.</p>
<p><img src="/lesson/running-a-container/docker-rm.jpg" alt="docker rm"></p>
<h2>The <code>--rm</code> flag</h2>
<p>What we really want to do most of the time is have a container auto-remove itself once we’re done with it. To do that, you can use the <code>--rm</code> flag with <code>docker run</code>, and that will instruct Docker to remove the container when it exits.</p>
<p>So go ahead and run that command now:</p>
<pre><code class="language-bash">docker run -it --rm php bash
</code></pre>
<p>Once you’re in the container, go ahead and type <code>exit</code> and press return to exit the container. And now if you run <code>docker ps -a</code> you’ll see that the container is not listed.</p>
<h2>Running a command then exiting with <code>-c</code></h2>
<p>Something that may be a little more useful most of the time than dropping into a command line session in a container is running a command then exiting.</p>
<p>For the purposes of illustration, I’ll show running the <code>ls</code> command to list files and directories inside the Docker container — which is probably not all that useful in your day-to-day Docker activities, but it should give you an idea of how to run commands.</p>
<p>We’ll continue building on the same command we used before: <code>docker run -it --rm php bash</code>, but now we’ll add the <code>-c</code> option with a command to run. To run <code>ls</code> that would be like this:</p>
<pre><code class="language-bash">docker run -it --rm php bash -c &quot;ls -lah&quot;
</code></pre>
<p>That will print out the list of files and directories in the working directory of the image and then exit.</p>
<p><img src="/lesson/running-a-container/docker-run-ls-lah.jpg" alt="docker run ls -lah"></p>
<p>And because we used the <code>--rm</code> flag, the exited container will also be removed once it has finished running the command.</p>
<h2>Running the <code>php:apache</code> image</h2>
<p>Now let’s do something a little more useful. We will now get the <code>php:apache</code> image running and serving a website. The PHP images all have Apache tag variants with a basic Apache setup ready to go and serve a website.</p>
<p>In order to serve a website from <code>docker run</code> with that image, we’ll need to specify a port mapping — which we talked about briefly in the <a href="/lesson/key-concepts">Docker Key Concepts lesson</a>.</p>
<p>The basic concept is this: map an unused port on your localhost, to the port the Docker container is serving content over. For websites that will be port 80.</p>
<div class="markdown-alert markdown-alert-note"><p class="markdown-alert-title"><svg class="octicon octicon-info mr-2" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path></svg>Note</p><p>You can also, of course, configure Apache to serve SSL and HTTPS with SSL certificates over port 443, which is beyond the scope of our lesson here, but do know that it’s certainly possible to do that.</p>
</div>
<p>To do the port mapping with the <code>docker run</code> command, we’ll need to use the <code>-p</code> option. For the purposes of this demo command, I’ll use <code>9000</code> for the port on the host. That is probably unused on your localhost as well. If it is in use, you can choose any other unused port. Here’s the command:</p>
<pre><code class="language-bash">docker run -it --rm -p 9000:80 php:apache
</code></pre>
<p>The port on the left side of the colon is the port to use on your localhost, and the port on the right side of the colon is the one to map to inside the container. So with that command above, if you hit <a href="http://localhost:9000">http://localhost:9000</a> on your localhost, it will hit port 80 inside the container.</p>
<p>Go ahead and run that command now. Once it’s running (if you’ve never used that image before, Docker will need to download it first), Apache is now ready to receive connections. Go ahead and load <a href="http://localhost:9000">http://localhost:9000</a> in your browser.</p>
<p>Now, of course, there’s nothing for Apache to serve in this container, so you’ll get an error message from Apache.</p>
<p><img src="/lesson/running-a-container/apahce-error.jpg" alt="Apache Error"></p>
<p>But in this case an error message is actually good if it’s coming from the container and Apache. It means the Apache container is online and serving things through the port map.</p>
<p>And now at this point if you send the interrupt signal (ctrl + c) to your terminal running the <code>php:apache</code> container, it should shut down and the exited container should be removed.</p>
<h2>Mounting a directory with an index.php file for <code>php:apache</code> to serve</h2>
<p>Now we’re going to get Apache and PHP to serve up some very simple PHP through that Docker container. In order to do that, create a directory called <code>php-example</code>. Then place an <code>index.php</code> file in that directory with the following contents:</p>
<pre><code class="language-php">&lt;?php

echo 'hello world';
</code></pre>
<p>The command we’ll run to serve this index file is as follows:</p>
<pre><code class="language-bash">docker run -it --rm -p 9000:80 -v $(pwd):/var/www/html php:apache
</code></pre>
<p>Let’s break down the new part of this command here. We’re using the <code>-v</code> option (<code>v</code> stands for “volume”) to mount a local file system resource on the local computer into the running Docker container. <code>pwd</code> stands for “print working directory” so it prints out the current location of your bash session into that command on the left side of the colon. The left side of the colon is the “source” path of the local filesystem resource.</p>
<p>On the right side of the colon is the path to mount the filesystem resource into in the running container. In this case, we’re putting it where the default Apache configuration in the container expects to serve from.</p>
<p>So armed with that knowledge, from a bash session <code>cd</code>ed into the <code>php-example</code> directory, run the command above. Once that’s running, load up <a href="http://localhost:9000">http://localhost:9000</a> in your browser again. You should see your successful “hello world” page.</p>
<p><img src="/lesson/running-a-container/php-apache-hello-world.jpg" alt="Hello World"></p>
<p>For bonus points, you can edit the “hello world” response to be something else, refresh the page, it should be reflected there.</p>
<p><img src="/lesson/running-a-container/hello-blue-ocean-docker-readers.jpg" alt="Hello Blue Ocean Docker Readers"></p>
<h2>Other applications</h2>
<p>The usefulness of Docker becomes more apparent and more powerful when you realize you can use it to run and manage versions of software and applications that are different across projects and services. For example, let’s say that we have an older project that is running Node 12 (yes, yes, I know, very outdated — that could <em>never</em> happen in the real world to a real project…). With Docker, it becomes trivial to use a Docker image of Node 12 for that project, and not have to manage various versions of various projects and software stacks.</p>
<p>To install <code>yarn</code> dependencies in that node project, you could do something like this:</p>
<pre><code class="language-bash">docker run -it --rm -v $(pwd):/app -w /app node:12 bash -c &quot;yarn&quot;
</code></pre>
<p>That makes things super simple, and version control of engines and languages easy. And that’s just a small taste of the power of Docker.</p>
<p>In future lessons, we’ll explore how to create projects and multi-container environments that keep themselves running with <a href="https://docs.docker.com/compose/">Docker Compose</a>, and how to take that all out to production.</p>]]></description><link>https://www.blueoceandocker.com/lesson/running-a-container</link><guid isPermaLink="false">IuQXVzaQyoI</guid><dc:creator><![CDATA[TJ Draper]]></dc:creator><pubDate>Sun, 20 Aug 2023 06:00:00 GMT</pubDate></item><item><title><![CDATA[Lesson 2: Key Concepts]]></title><description><![CDATA[Learn about the important key concepts of Docker<br><br><iframe width="560" height="315" src="https://www.youtube.com/embed/aRB2a70Teuk" title="Lesson 2: Key Concepts" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe><br><br>If you prefer to read the lesson, rather than watch the video, I’ve got you covered!<h3>Lesson article:</h3><hr /><h1>Docker Key Concepts</h1>
<p>When trying to understand any technology, often the best place to start is with the key concepts. And so in this lesson, we’ll give you a basic understanding of some of the fundamental concepts in the Docker landscape.</p>
<h2>Containerization Technology</h2>
<p><img src="/lesson/key-concepts/key-concepts.001.jpg" alt="Docker is a Containerization Technology"></p>
<p>The first thing to understand is that Docker is a containerization technology. Now, you may be saying, “Great! but what does that mean, exactly?”</p>
<p>Well, in the Docker context, a container is a bundle of software and all that software’s dependencies, packaged together in an environment that it can run in. The goal of this packaging it to abstract away the hosting platform and give the application the same environment to run in, every time and every place that it may run.</p>
<p><img src="/lesson/key-concepts/key-concepts.002.jpg" alt="Containerization with Docker packages up everything you need"></p>
<p>Containerization with Docker packages up everything needed to run an application: this includes:</p>
<ul>
<li>the lower level binaries on the server</li>
<li>all the libraries</li>
<li>configuration</li>
<li>dependencies of the application</li>
</ul>
<p>Containerization abstracts the host platform that your application is running on, and removes differences between environments that make bugs difficult to track down.</p>
<p>Notably, this is <strong>not</strong> accomplished with virtual machines. Perhaps you remember the days when many developers were using virtual machines both in local development and even in production environments. These tended to have poor performance and a host of other problems. With Docker, performance will be native, or near the native speeds you’d see if you ran all the software on the server outside of Docker.</p>
<div class="markdown-alert markdown-alert-note"><p class="markdown-alert-title"><svg class="octicon octicon-info mr-2" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path></svg>Note</p><p>While I’ll cover some of the most basic concepts to help you understand how Docker works, if you’d like a deeper dive into the technical, I recommend this article on Citrix.com titled, “<a href="https://www.netscaler.com/articles/what-is-containerization">What is Containerization</a>.”</p>
</div>
<h2>Images</h2>
<p>Now let’s turn our attention to the concept of “Images.”</p>
<p><img src="/lesson/key-concepts/key-concepts.003.jpg" alt="Docker Images"></p>
<p>In the Docker world, images are what we call the containerized bundles of libraries and code. Docker images are used to run a container (which we’ll define in a moment). Docker images are created using the <code>docker build</code> command from the instructions developers put in Dockerfiles. The created images are self-contained bundles of libraries and code. You can liken a Docker image to an inert, immutable file. It’s essentially a snapshot that should have everything needed to run the application.</p>
<div class="markdown-alert markdown-alert-tip"><p class="markdown-alert-title"><svg class="octicon octicon-light-bulb mr-2" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="M8 1.5c-2.363 0-4 1.69-4 3.75 0 .984.424 1.625.984 2.304l.214.253c.223.264.47.556.673.848.284.411.537.896.621 1.49a.75.75 0 0 1-1.484.211c-.04-.282-.163-.547-.37-.847a8.456 8.456 0 0 0-.542-.68c-.084-.1-.173-.205-.268-.32C3.201 7.75 2.5 6.766 2.5 5.25 2.5 2.31 4.863 0 8 0s5.5 2.31 5.5 5.25c0 1.516-.701 2.5-1.328 3.259-.095.115-.184.22-.268.319-.207.245-.383.453-.541.681-.208.3-.33.565-.37.847a.751.751 0 0 1-1.485-.212c.084-.593.337-1.078.621-1.489.203-.292.45-.584.673-.848.075-.088.147-.173.213-.253.561-.679.985-1.32.985-2.304 0-2.06-1.637-3.75-4-3.75ZM5.75 12h4.5a.75.75 0 0 1 0 1.5h-4.5a.75.75 0 0 1 0-1.5ZM6 15.25a.75.75 0 0 1 .75-.75h2.5a.75.75 0 0 1 0 1.5h-2.5a.75.75 0 0 1-.75-.75Z"></path></svg>Tip</p><p>Think of a Docker Image like a snapshot of a given time and state. The Docker Image is a frozen snapshot state of the application at the time the image was created.</p>
</div>
<h2>Container Registries</h2>
<p><img src="/lesson/key-concepts/key-concepts.004.jpg" alt="Container Registries"></p>
<p>Images exist in “container registries,” which, unfortunately, is a name I find a tad confusing because containers are distinct from images. Nevertheless, the created images have to live somewhere, and that somewhere is container registries. Your dev environment, build server, staging server, and your production server will all have a local cache or store of images, and those locally stored images are downloaded from remote container registries. <a href="https://hub.docker.com/">hub.docker.com</a> is the default, public container registry, but you can also host your own private registries or use services that provide private registries such as GitHub, Digital Ocean, and more.</p>
<h2>Containers</h2>
<p><img src="/lesson/key-concepts/key-concepts.005.jpg" alt="Containers"></p>
<p>And what do you do with those images? You create containers. Containers are what we call the running images. According to <a href="https://www.docker.com/resources/what-container/">Docker’s documentation</a>, “Images become containers at runtime.” So, containers run “from” an image.</p>
<div class="markdown-alert markdown-alert-tip"><p class="markdown-alert-title"><svg class="octicon octicon-light-bulb mr-2" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="M8 1.5c-2.363 0-4 1.69-4 3.75 0 .984.424 1.625.984 2.304l.214.253c.223.264.47.556.673.848.284.411.537.896.621 1.49a.75.75 0 0 1-1.484.211c-.04-.282-.163-.547-.37-.847a8.456 8.456 0 0 0-.542-.68c-.084-.1-.173-.205-.268-.32C3.201 7.75 2.5 6.766 2.5 5.25 2.5 2.31 4.863 0 8 0s5.5 2.31 5.5 5.25c0 1.516-.701 2.5-1.328 3.259-.095.115-.184.22-.268.319-.207.245-.383.453-.541.681-.208.3-.33.565-.37.847a.751.751 0 0 1-1.485-.212c.084-.593.337-1.078.621-1.489.203-.292.45-.584.673-.848.075-.088.147-.173.213-.253.561-.679.985-1.32.985-2.304 0-2.06-1.637-3.75-4-3.75ZM5.75 12h4.5a.75.75 0 0 1 0 1.5h-4.5a.75.75 0 0 1 0-1.5ZM6 15.25a.75.75 0 0 1 .75-.75h2.5a.75.75 0 0 1 0 1.5h-2.5a.75.75 0 0 1-.75-.75Z"></path></svg>Tip</p><p>I like to bring in a programming metaphor to help explain, and if you’re familiar with object-oriented programming this will make some sense to you:</p>
<p>Think of an image like a class, and a container like an instance of that class. So, just like a class is the definition or blueprint from which an instance is created, so is a Docker image. A container is constructed from the blueprint of the Docker image just like a class instance is constructed from a class definition.</p>
</div>
<h2>Ephemerality</h2>
<p><img src="/lesson/key-concepts/key-concepts.006.jpg" alt="Ephemerality"></p>
<p>Recall that I mentioned that images were inert and, importantly, immutable. Once an image is created it doesn’t change. To change an image, you build a new image. That’s why it’s important here to talk about the ephemeral nature of anything that happens inside a container. Unless you take steps of preservation, anything you do inside a running container is ephemeral. When an image stops running, anything you “saved to disk” is gone. This is, obviously, very important to know. So now you might be thinking, “what is the point then?”</p>
<h3>Volumes</h3>
<p>Docker has provided a way to handle permanence. And that way is volumes.</p>
<p><img src="/lesson/key-concepts/key-concepts.007.jpg" alt="Volumes"></p>
<p>Volumes are the mechanism for persisting data across container stops and starts, new containers being brought online to replace old ones, etc. A volume is just a local filesystem resource such as a file or a directory mounted into a running container at a specified mount point. If you know anything about unix mount points, Docker Volumes work in exactly the same way. You can define a file path on the host to mount into the running container, or you can tell Docker to create a volume, manage it, and mount it into the running container.</p>
<div class="markdown-alert markdown-alert-note"><p class="markdown-alert-title"><svg class="octicon octicon-info mr-2" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path></svg>Note</p><p>If you want a deeper technical dive into Volumes, I recommend this article on container-solutions.com titled, “<a href="https://blog.container-solutions.com/understanding-volumes-docker">Understanding Volumes in Docker</a>.”</p>
</div>
<h2>Docker Compose</h2>
<p><img src="/lesson/key-concepts/key-concepts.008.jpg" alt="Docker Compose"></p>
<p>Last, but, certainly not least in our key concept exploration, we’ll explore Docker Compose.</p>
<p>Many of your applications may need more than one container and Docker Compose is the way you can define a multi-container environment. You will, of course, need a container to run your app, but you may also want to run containers for things like Redis, MongoDB, or MySQL. Or, a common need I’ve had is to spin up containers as services that will, essentially, run cron jobs (or, the equivalent). These may use the same image as your primary application container — which is just another beauty of Docker and the image-based ecosystem. Whatever the need, you will almost certainly need to define more than one container for many of your applications.</p>
<p>And even if you have only one container in your application, it’s still very useful to define the various things your container will need, volume mounts being one example.</p>
<p>Let’s look over a very simple and truncated Docker Compose file.</p>
<div class="markdown-alert markdown-alert-note"><p class="markdown-alert-title"><svg class="octicon octicon-info mr-2" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path></svg>Note</p><p>Docker Compose files are written in YAML. YAML is quite common as a configuration language these days, and that’s what Docker Compose uses. It’s a very readable language in which indentations define the relationship of children and parents. It’s a pretty simple language to pick up, and you can certainly find more online if you need to know the basics of the language.</p>
</div>
<p>In this example, I’ve created a simple Docker Compose YAML file (<code>docker-compose.yml</code>) that defines a couple of containers, and a managed volume.</p>
<pre><code class="language-yaml">services:
  app:
    image: php:apache-buster
    ports:
      - &quot;5000:80&quot;
    volumes:
      - .:/var/www/app:delegated
  database:
    image: mariadb
    ports:
      - &quot;5100:3306&quot;
    environment:
      MYSQL_ROOT_PASSWORD: root
    volumes:
      - db-volume:/var/lib/mysql:delegated
  redis:
    image: redis:alpine
volumes:
  db-volume:
</code></pre>
<p>A Docker Compose file needs an array of “services.” Each key in this array defines a container. For instance, I’ve used a key named “app” to define my primary application container. For the app, I’m using a vanilla PHP image, but this could be any image that suites your app’s needs.</p>
<p>For the purposes of development and this demo, I’m doing some port mapping (<code>&quot;5100:3306&quot;</code>). With the port mapping, I’m telling Docker that when I access my machine’s local host on port 5000, it should map that to port 80 in the container. This is something you would only do for your local dev, and not something you would do in production. In fact, if you’re using Docker Swarm in production, which is what I recommend if you’re running you’re own Docker server, this setting won’t even have any effect. There are also a variety of ways around port mapping in local dev which are beyond the scope of our key concepts here.</p>
<p>You can also see in the examples that I’ve defined some volumes for our app container. In this case, again, for local dev (not something you’d do in production), I’ve mounted the entire codebase on my computer’s filesystem to <code>/var/www/app</code> in the container. I’ve also used the <code>:delegated</code> flag, which will give your local dev environment a slight I/O speed increase. You can read more in Docker’s documentation. This, again, is for local development. In production, you would typically build all of your application’s files into the image. But you don’t want to run a build every time you make a change to files when you’re actively developing.</p>
<p>In the example I’ve also defined a database container. You can certainly run this in production, particularly on smaller apps. But in larger application environments, you may not be running a database container in your Docker stack, you may only need this for local dev and connect to a managed database in production. So that’s something to keep in mind. In any event, in the example I’m using a container to run MariaDB. And I’ve set up a volume for Docker to manage that MariaDB data will be stored in. In the volumes definition array, I’ve given the volume a name. This means Docker will create and manage a volume for me and I don’t have to worry about it or where it’s at. And then up in the container definition, I’ve mounted the volume at the point where MariaDB expects to find its data. Since MariaDB is a drop-in MySQL replacement, that path is <code>/var/lib/mysql</code></p>
<hr>
<p>And those are the key concepts to keep in mind as we move forward in understanding how to leverage Docker. In future lessons, we’ll start seeing all these concepts in action!</p>]]></description><link>https://www.blueoceandocker.com/lesson/key-concepts</link><guid isPermaLink="false">aRB2a70Teuk</guid><dc:creator><![CDATA[TJ Draper]]></dc:creator><pubDate>Sun, 23 Jul 2023 00:40:00 GMT</pubDate></item><item><title><![CDATA[Lesson 1: Why Docker]]></title><description><![CDATA[Learn about why you would want to use Docker and how it can benefit you!<br><br><iframe width="560" height="315" src="https://www.youtube.com/embed/J3fk7fNMxGo" title="Lesson 1: Why Docker" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe><br><br>If you prefer to read the lesson, rather than watch the video, I’ve got you covered!<h3>Lesson article:</h3><hr /><h1>Why Docker?</h1>
<p>At this point, you’ve probably heard of Docker. Its usage has grown by leaps and bounds. But what is Docker? What does it do? How does it work? What purpose does Docker serve? Well, there’s a good reason Docker has taken the web development and server world by storm. Docker upends the way traditional web application stacks work and how we think about them and gives us a much better model of application architecture management.</p>
<p>Let’s start with local development. Any developer is going to need an environment in which to run their application for development and testing. Most developers use more than one environment. In the web world, we have to run the entire web application stack in order to serve the application we’re working on to a browser so we can see the result of the code we’re writing.</p>
<p>If, for instance, you have an application that runs a Node based React front-end and a PHP back-end. You’ll need a web server and PHP, and you’ll probably need a database, whether that’s MySQL, Postgres, Mongo, or one of the other myriad available database engines. And you’ll need a Node installation to run the Node application, probably using Express or some framework built-in tooling (which is likely running Express somewhere behind the scenes). This means you have to install a lot of stuff on your computer and keep it at the right version for your application.</p>
<p>There have been various tools for getting this done over the years. You may have heard of some of them: MAMP, XAMPP, Vagrant, EasyPHP, Virtalbox, Laravel Valet — or maybe you’ve used Homebrew to install these tools directly on your computer.</p>
<p>But these solutions have some of fatal flaws. Let’s consider two of them:</p>
<p>The first is that it can take a while to get started on a new or existing project. You may have to install new or different versions of your various application stacks, and you may have to manage those versions in some way so that they don’t clash with the versions required to run other application stacks that you also work on.</p>
<p>The second issue of concern is that using older and more traditional methods of running your application on your local computer means that you are working in an environment that your application will ultimately not be running in. To put this in context and illustrate why it’s important, let’s say that you write a feature that requires a certain PHP extension to be loaded — and that extension is loaded by default in the environment you’re working in. But when you deploy to production your app crashes because that extension isn’t loaded in that environment. And then you have the dreaded, “well, it works on my machine.” And now you have to track down an incredibly hard to find bug that you can’t replicate in your development environment. The quip to, “well, it works on my machine,” is usually, “but we’re not shipping your machine to the user are we?”</p>
<p>But what if we could?</p>
<p>Docker, when leveraged to its full potential, essentially makes this possible.</p>
<p>In the following lessons, we’ll cover things like the terminology that Docker uses (what is a container, what’s an image, and what’s the difference), how to set up an environment that you can use from dev to production, and how you can make the most of Docker.</p>]]></description><link>https://www.blueoceandocker.com/</link><guid isPermaLink="false">J3fk7fNMxGo</guid><dc:creator><![CDATA[TJ Draper]]></dc:creator><pubDate>Mon, 17 Jul 2023 14:00:00 GMT</pubDate></item></channel></rss>