<?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" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[Bahadır Yağan - Blog]]></title><description><![CDATA[Thoughts, stories and ideas.]]></description><link>https://www.taypo.com/</link><image><url>https://www.taypo.com/favicon.png</url><title>Bahadır Yağan - Blog</title><link>https://www.taypo.com/</link></image><generator>Ghost 3.42</generator><lastBuildDate>Sun, 22 Mar 2026 23:24:27 GMT</lastBuildDate><atom:link href="https://www.taypo.com/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[Keeping Javascript Simple]]></title><description><![CDATA[<p><em>Edit: This was previously published on May 2017 on another platform.</em></p><p>Constant discussions about the state of frontend development are going for a while now. And they all touched a nerve or two for everyone. The amount of tools and libraries you need to integrate and keep track of is</p>]]></description><link>https://www.taypo.com/keeping-javascript-simple/</link><guid isPermaLink="false">65957da5eadd94000112ca5c</guid><dc:creator><![CDATA[Bahadır Yağan]]></dc:creator><pubDate>Wed, 03 Jan 2024 15:42:25 GMT</pubDate><content:encoded><![CDATA[<p><em>Edit: This was previously published on May 2017 on another platform.</em></p><p>Constant discussions about the state of frontend development are going for a while now. And they all touched a nerve or two for everyone. The amount of tools and libraries you need to integrate and keep track of is increasing rapidly. Mix it with the efforts of trying to fix javascript (ES6+) and you forget what you were going to do in the first place.</p><p>So I was looking for a way back to the old ways of <strong><em>&lt;script src=”jquery.js”/&gt;</em></strong> but still be able to use a modern library employing aproaches like javascript components, one way data flow, easy and fast dom updates.</p><p>I believe my search is over. <a href="https://vuejs.org" rel="noopener">Vue.js</a> is a frontend framework that can be <a href="https://vuejs.org/v2/guide/installation.html#Direct-lt-script-gt-Include" rel="noopener">directly included</a> from your html files, and it is comparable to Angular and React. In this post I want to describe how I use it to have a modern environment without dealing with the likes of npm, webpack, babel, typescript etc..</p><p>To go over the specifics of my setup, I put together a simple <a href="https://keep.google.com" rel="noopener">Google Keep</a> clone just for this post. The code is on <a href="https://github.com/taypo/keepclone" rel="noopener">github</a>, and there is a running <a href="http://keepclone.taypo.com/" rel="noopener">demo </a>that you can check out. The demo does not save anything for obvious reasons.</p><figure class="kg-card kg-image-card"><img src="https://www.taypo.com/content/images/2024/01/image.png" class="kg-image" alt srcset="https://www.taypo.com/content/images/size/w600/2024/01/image.png 600w, https://www.taypo.com/content/images/size/w1000/2024/01/image.png 1000w, https://www.taypo.com/content/images/2024/01/image.png 1114w" sizes="(min-width: 720px) 720px"></figure><h4 id="ui-components">UI Components</h4><p>To implement the very basic functionality of Google Keep, three components seems enough. One to view notes, one to create and another one to wrap the note editor in a modal box. Their code can be found from the same <a href="https://github.com/taypo/keepclone/tree/master/src/main/resources/templates/components" rel="noopener">github repository.</a></p><h4 id="backend">Backend</h4><p>Coming from a long Java background, my backend of choice is <a href="https://projects.spring.io/spring-boot/" rel="noopener">Spring Boot</a>. It has all the goodies of spring with none of the configuration hassle. But I am not going into any details as it is not the intent of this post. We will also use <a href="http://www.thymeleaf.org/" rel="noopener">Thymeleaf</a> as the server side template engine. It will help with the methods used in the next two sections.</p><h4 id="preloading-data">Preloading Data</h4><p>To decrease the number of requests going to the server, you can insert the list of notes to the initial page. Just loading the notes from DB and adding to the mvc model, they will be converted to JSON with thymeleaf’s inline javascript function.</p><!--kg-card-begin: html--><script src="https://gist.github.com/taypo/1e5ed6b72bd577ecadb8199e3a2b95b1.js"></script><!--kg-card-end: html--><pre><code class="language-javascript">/*[[${notes}]]*/</code></pre><p>This line is replaced with the JSON representation of the notes when thymeleaf processes the template.</p><h4 id="single-file-components">Single File Components</h4><p>Vue.js has a feature called <a href="https://vuejs.org/v2/guide/single-file-components.html" rel="noopener">single file components</a>. The idea is to keep the template, style and the javascript of a component together. This can be partially done with thymeleaf includes. Since style tags outside of head tag works in recent browsers, it usually works. Unlike .vue files, this approach does not solve name collisions, so be careful.</p><p>Here is the simple code for the note view component.</p><!--kg-card-begin: html--><script src="https://gist.github.com/taypo/0ff8101a07d1234acc3b015d18246058.js"></script><!--kg-card-end: html--><h4 id="the-future">The Future</h4><p>I am using this approach on a medium sized project and wish to avoid the dark side of javascript for as long as possible. And the trends looks good too.</p><figure class="kg-card kg-image-card"><img src="https://www.taypo.com/content/images/2024/01/image-1.png" class="kg-image" alt srcset="https://www.taypo.com/content/images/size/w600/2024/01/image-1.png 600w, https://www.taypo.com/content/images/2024/01/image-1.png 604w"></figure>]]></content:encoded></item><item><title><![CDATA[Easily Create a Nomad Cluster Locally with Multipass]]></title><description><![CDATA[<p><a href="https://multipass.run">Multipass</a> is a great tool from Canonical, that lets you create any number of Ubuntu virtual machines to play with. It works on Windows, Mac and Linux with their native hypervisors. Launching a new VM is as easy as:</p><pre><code class="language-bash">multipass launch</code></pre><p>Checkout these VMs on my work laptop. </p><pre><code class="language-bash">bahadir@N45ZA23:</code></pre>]]></description><link>https://www.taypo.com/easily-create-a-nomad-cluster/</link><guid isPermaLink="false">5e907395fa65d70001e88c47</guid><category><![CDATA[multipass]]></category><category><![CDATA[nomad]]></category><dc:creator><![CDATA[Bahadır Yağan]]></dc:creator><pubDate>Mon, 27 Apr 2020 14:15:32 GMT</pubDate><media:content url="https://www.taypo.com/content/images/2020/04/Nomad-1.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://www.taypo.com/content/images/2020/04/Nomad-1.jpg" alt="Easily Create a Nomad Cluster Locally with Multipass"><p><a href="https://multipass.run">Multipass</a> is a great tool from Canonical, that lets you create any number of Ubuntu virtual machines to play with. It works on Windows, Mac and Linux with their native hypervisors. Launching a new VM is as easy as:</p><pre><code class="language-bash">multipass launch</code></pre><p>Checkout these VMs on my work laptop. </p><pre><code class="language-bash">bahadir@N45ZA23:~$ multipass list
Name                    State                 Image
kubenode1               Stopped               Ubuntu 18.04 LTS
kubenode2               Stopped               Ubuntu 18.04 LTS
kubenode3               Stopped               Ubuntu 18.04 LTS
nomadcli1               Stopped               Not Available
nomadcli2               Stopped               Not Available
nomadcli3               Stopped               Not Available
nomadsrv1               Stopped               Not Available
patroni1                Stopped               Ubuntu 18.04 LTS
patroni2                Stopped               Ubuntu 18.04 LTS
patroni3                Stopped               Ubuntu 18.04 LTS</code></pre><p>I'm currently testing other tools as well, so I needed a local Kubernetes cluster, a Nomad cluster and a replicated PostgreSQL cluster built with <a href="https://github.com/zalando/patroni">Patroni</a>. All of them installed on my Linux laptop using Multipass. Cool!</p><h2 id="nomad">Nomad</h2><p>Now coming back to our main topic, how you can easily create a <a href="https://www.nomadproject.io">Nomad</a> cluster with Multipass. There are already ways of doing this using Vagrant and/or Ansible. But using <a href="https://github.com/taypo/multipass-images">these custom images</a> I built for Multipass, I think it is simpler now.</p><p>The setup we are trying to achieve is this:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.taypo.com/content/images/2020/04/Nomad.jpg" class="kg-image" alt="Easily Create a Nomad Cluster Locally with Multipass"><figcaption>Dotted notebooks are great!</figcaption></figure><p>Since this is a test setup, there is no need to run a separate Consul cluster. Both servers can run on a single node. I created two custom Multipass images, one for the server and the other for the clients. The scripts to build the images are on the following github repository:</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://github.com/taypo/multipass-images"><div class="kg-bookmark-content"><div class="kg-bookmark-title">taypo/multipass-images</div><div class="kg-bookmark-description">My custom multipass images for local development and testing use - taypo/multipass-images</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://github.githubassets.com/favicons/favicon.svg" alt="Easily Create a Nomad Cluster Locally with Multipass"><span class="kg-bookmark-author">taypo</span><span class="kg-bookmark-publisher">GitHub</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://avatars2.githubusercontent.com/u/1873400?s=400&amp;v=4" alt="Easily Create a Nomad Cluster Locally with Multipass"></div></a></figure><p>These are done using another HashiCorp tool, <a href="https://www.packer.io">Packer</a>. Building those images are not our concern for this post, so I'm going to use the pre-built images.</p><blockquote>Warning: At the time of writing, custom images are supported only for the Linux version of Multipass.</blockquote><h3 id="steps-to-launch-the-cluster">Steps to Launch the Cluster</h3><p>Run the server.</p><pre><code class="language-bash">multipass launch https://img.taypo.com/nomad-server.img --name NomadServer</code></pre><p>Get the IP address of this VM from <code>multipass info NomadServer</code>.</p><p>Consul clients need to know the IP's of the servers. We need to add  a simple Consul config line to clients images. Multipass supports <a href="https://cloud-init.io">cloud-init</a> for customizing images. Create a file <code>cloudinit.yml</code> and put the IP address of the server in it.</p><pre><code class="language-yaml">write_files:
-   content: |
        retry_join = ["put your nomad server ip between these quotes"]
    path: /etc/consul.d/join.hcl</code></pre><p>Now you can launch as many clients as you want.</p><pre><code class="language-bash">multipass launch https://img.taypo.com/nomad-client.img --name NomadClient1 --cloud-init cloudinit.yml
multipass launch https://img.taypo.com/nomad-client.img --name NomadClient2 --cloud-init cloudinit.yml
multipass launch https://img.taypo.com/nomad-client.img --name NomadClient3 --cloud-init cloudinit.yml</code></pre><p>Consul UI will be running on port 8500 of the server. And Nomad UI on 4646. Here is the whole thing in under five minutes.</p><!--kg-card-begin: html--><iframe width="700" height="394" src="https://www.youtube.com/embed/ittLU1v6siQ" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe><!--kg-card-end: html--><p>Client images come with docker installed, so you can submit docker jobs, <a href="https://learn.hashicorp.com/nomad/managing-jobs/submitting-jobs">such as this</a>, to test your cluster.</p><h3 id="vm-sizing">VM Sizing</h3><p>Multipass creates all the VM's with default sizing of 1 GB memory, 1 CPU and 5 GB of disk. All of those can be changed with parameters to <code>multipass launch</code></p><pre><code>bahadir@N45ZA23:~/dev/blog$ multipass help launch 

  -c, --cpus &lt;cpus&gt;    Number of CPUs to allocate.
                       Minimum: 1, default: 1.
  -d, --disk &lt;disk&gt;    Disk space to allocate. Positive integers, in bytes, or
                       with K, M, G suffix.
                       Minimum: 512M, default: 5G.
  -m, --mem &lt;mem&gt;      Amount of memory to allocate. Positive integers, in
                       bytes, or with K, M, G suffix.
                       Minimum: 128M, default: 1G.
</code></pre>]]></content:encoded></item><item><title><![CDATA[Docker As a Build Tool]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>Suppose you want to build a java maven project, but you don't have the correct environment to do so. Or you just don't want to mess up your local machine. You can use docker to do the build without installing JDK or Maven.</p>
<p>We are going to use <a href="https://github.com/spring-projects/spring-petclinic">Spring PetClinic</a></p>]]></description><link>https://www.taypo.com/docker-as-a-build-tool/</link><guid isPermaLink="false">5e907395fa65d70001e88c46</guid><category><![CDATA[docker]]></category><category><![CDATA[maven]]></category><dc:creator><![CDATA[Bahadır Yağan]]></dc:creator><pubDate>Mon, 10 Oct 2016 16:08:00 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>Suppose you want to build a java maven project, but you don't have the correct environment to do so. Or you just don't want to mess up your local machine. You can use docker to do the build without installing JDK or Maven.</p>
<p>We are going to use <a href="https://github.com/spring-projects/spring-petclinic">Spring PetClinic</a> application as a sample for this post. Let's start by checking out the sources from github.</p>
<pre><code class="language-language-bash">git clone https://github.com/spring-projects/spring-petclinic.git
</code></pre>
<p>Change into the directory.</p>
<pre><code class="language-language-bash">cd spring-petclinic
</code></pre>
<p>Now for the magic part:</p>
<pre><code class="language-language-bash">docker run -it --rm -v &quot;$PWD&quot;:/work -w /work \
  maven:3.3.9-jdk-7 mvn package
</code></pre>
<p>Here we are running the maven docker image <strong>maven:3.3.9-jdk-7</strong>. You can choose different java and maven versions from the <a href="https://hub.docker.com/_/maven/">docker repository</a> according to your project needs. We also added the current directory as a volume mounted to <strong>/work</strong>.</p>
<p>Docker command will take some time to complete. It will get the container image first, if its not downloaded before. The container just runs <code>mvn package</code> when the image is downloaded and started. Than maven will fetch all its dependencies, run the tests and build the project artifacts. <strong>petclinic.war</strong> in this case. After the build is complete the container will exit and remove itself (<strong>-rm</strong>) from the docker server.</p>
<p>Build results will be inside the target directory on your local file system:</p>
<pre><code class="language-language-bash">$ ls -1 target/
classes
generated-sources
generated-test-sources
maven-archiver
maven-status
petclinic
petclinic.war
surefire-reports
test-classes
</code></pre>
<h3 id="persistentmavenrepository">Persistent Maven Repository</h3>
<p>Above procedure can be optimized by making the maven repository persistent between further runs. You'll save loads of time and bandwith by not downloading all the dependencies for every build.</p>
<p>Docker volumes to the rescue.</p>
<pre><code class="language-language-bash">docker volume create --name m2repo
</code></pre>
<p>And add this volume when running the container.</p>
<pre><code class="language-language-bash">docker run -it --rm -v &quot;$PWD&quot;:/work -v m2repo:/root/.m2 -w /work \
  maven:3.3.9-jdk-7 mvn package
</code></pre>
<p>only difference here is the second -v parameter that maps the volume we just created to <code>/root/.m2</code> directory.</p>
<p>This optimization dropped the build time to 90 seconds from 200 seconds on my old mac with a decent network.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Elegant Data Initialization for Spring Projects]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>So you want some initial data to be available to your spring project. You can use Hibernate's <a href="https://docs.spring.io/spring-boot/docs/current/reference/html/howto-database-initialization.html#howto-initialize-a-database-using-hibernate"><code>import.sql</code></a> but let's do it with Java 8 and Spring Data JPA Repositories.</p>
<p><strong>Case:</strong> Make sure there is an admin user, if not create one with desired roles. (Sample Data: <code>username: admin</code></p>]]></description><link>https://www.taypo.com/elegant-data-initialization-for-spring-boot-projects/</link><guid isPermaLink="false">5e907395fa65d70001e88c44</guid><category><![CDATA[spring]]></category><category><![CDATA[spring-data]]></category><dc:creator><![CDATA[Bahadır Yağan]]></dc:creator><pubDate>Wed, 03 Feb 2016 14:44:51 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>So you want some initial data to be available to your spring project. You can use Hibernate's <a href="https://docs.spring.io/spring-boot/docs/current/reference/html/howto-database-initialization.html#howto-initialize-a-database-using-hibernate"><code>import.sql</code></a> but let's do it with Java 8 and Spring Data JPA Repositories.</p>
<p><strong>Case:</strong> Make sure there is an admin user, if not create one with desired roles. (Sample Data: <code>username: admin</code>, <code>password:admin</code> and has <code>ROLE_USER</code>, <code>ROLE_ADMIN</code> roles)</p>
<p><strong>Model:</strong></p>
<pre><code class="language-language-java">@Entity
public class Role {
    @Id
    private Long id;
    private String name;
    private String description;
}

@Entity
public class User {
    @Id
    private Long id;
    private String username;
    private String password;
    @ManyToMany
    private Set&lt;Role&gt; roles = new HashSet&lt;&gt;();
}

</code></pre>
<p><strong>Data JPA Repositories:</strong></p>
<pre><code class="language-language-java">public interface RoleRepository extends CrudRepository&lt;Role, Long&gt; {
    Optional&lt;Role&gt; findByName(String name);
}

public interface UserRepository extends CrudRepository&lt;User, Long&gt; {
    Optional&lt;User&gt; findByUsername(String username);
}
</code></pre>
<p><strong>Initialize Data:</strong></p>
<pre><code class="language-language-java">
@Component
public class Bootstrap implements InitializingBean {

    @Autowired RoleRepository roleRepo;
    @Autowired UserRepository userRepo;

    @Override
    public void afterPropertiesSet() throws Exception {
        Role roleUser= roleRepo.findByName(&quot;ROLE_USER&quot;)
                .orElseGet(() -&gt; 
                    roleRepo.save(new Role(&quot;ROLE_USER&quot;, &quot;User Role description&quot;))
                );

        Role roleAdmin = roleRepo.findByName(&quot;ROLE_ADMIN&quot;)
                .orElseGet(() -&gt; 
                    roleRepo.save(new Role(&quot;ROLE_ADMIN&quot;, &quot;Administrator Role description&quot;))
                );

        User user = userRepo.findByUsername(&quot;admin&quot;).orElseGet(() -&gt; {
            User u = new User(&quot;admin&quot;, &quot;admin&quot;);
            u.getRoles().add(roleUser);
            u.getRoles().add(roleAdmin);
            return userRepo.save(u);
        });
    }
}

</code></pre>
<ul>
<li>
<p>We make the class a <code>@Component</code> implementing <code>InitializingBean</code> interface. This will make sure <code>afterPropertiesSet()</code> method will be called for each startup, after the injections are complete.</p>
</li>
<li>
<p>Since our repositories return <code>Optional</code> values, we can use <code>orElseGet</code> on them to create domain objects if they don't already exist in the database. This was the Grails' way of writing bootstrap.groovy files. Don't know if it is still the case.</p>
</li>
<li>
<p>Above classes are simplified to give you the main point. Real life code probably will use Spring Security <code>GrantedAuthority</code> and <code>UserDetails</code> interfaces, and a <a href="http://docs.spring.io/spring-security/site/docs/current/apidocs/org/springframework/security/crypto/bcrypt/BCryptPasswordEncoder.html">password encoder</a>.</p>
</li>
</ul>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Ready to Use Jenkins Docker Image]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>For the past couple of weeks I've been working on a pre-configured Jenkins Docker image. I thought it should be easier to get started than the <a href="https://github.com/jenkinsci/docker">official jenkins image</a>.</p>
<p>Ultimate goal is to get the image to a point where no configuration, package management etc. is needed to add a</p>]]></description><link>https://www.taypo.com/jenkins-docker/</link><guid isPermaLink="false">5e907395fa65d70001e88c43</guid><category><![CDATA[docker]]></category><category><![CDATA[jenkins]]></category><dc:creator><![CDATA[Bahadır Yağan]]></dc:creator><pubDate>Sat, 12 Dec 2015 08:54:39 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>For the past couple of weeks I've been working on a pre-configured Jenkins Docker image. I thought it should be easier to get started than the <a href="https://github.com/jenkinsci/docker">official jenkins image</a>.</p>
<p>Ultimate goal is to get the image to a point where no configuration, package management etc. is needed to add a new Jenkins item, point to one of my repositories over at Bitbucket, make a maven build, and produce either a runnable jar or even better, another docker image that runs the jar.</p>
<p>You can check it out from <a href="https://hub.docker.com/r/taypo/jenkins/">dockerhub</a> or <a href="https://github.com/taypo/jenkins">github</a>.</p>
<h3 id="installedpackages">Installed Packages</h3>
<p>Below packages are pre-installed:</p>
<ul>
<li>Java 8 JDK</li>
<li>Maven 3</li>
<li>Git</li>
<li>Mercurial</li>
<li>Docker</li>
</ul>
<h3 id="features">Features</h3>
<h4 id="jenkinsconfiguration">Jenkins Configuration</h4>
<p>Jenkins is auto configured to use JDK and Maven installations of the system. Plugins for Git and Mercurial is also installed.</p>
<h4 id="sshclient">SSH Client</h4>
<p>Upon first start, the image generates an ssh key pair and prints the public key to the docker console. This is useful if your SCM provider requires public key cryptography for code checkouts. For example you can add this to your Bitbucket repository as a deployment key.</p>
<p>There is also an environment variable <code>KNOWN_HOSTS</code>. You can set comma separated list of host names to it, and their fingerprints are added to <code>~/.ssh/known_hosts</code>. This prevents your first checkout over ssh asking to add the host, thus blocking Jenkins.</p>
<h4 id="dockerbydocker">Docker <em>by</em> Docker</h4>
<p>Finally, we want our image to able to build docker images. Instead of using <a href="https://github.com/jpetazzo/dind">docker in docker</a> we can mount the unix socket file of the host docker deamon to this container, and build our images there. You can read more about how to access host docker, and why it is better than &quot;docker in docker&quot; in <a href="http://jpetazzo.github.io/2015/09/03/do-not-use-docker-in-docker-for-ci/">this blog post</a>.</p>
<h3 id="volumes">Volumes</h3>
<p>There are two volumes that you can mount to host, Jenkins data directory and root's <code>.ssh</code> directory.</p>
<pre><code class="language-language-bash">/var/jenkins_home
/root/.ssh
</code></pre>
<h3 id="running">Running</h3>
<p>Basic:</p>
<pre><code class="language-language-bash">docker run -p 8080:8080 -v taypo/jenkins
</code></pre>
<p>or with host mounted volumes, docker link and Bitbucket added to known hosts:</p>
<pre><code class="language-language-bash">docker run -p 8080:8080 \
-v /var/run/docker.sock:/var/run/docker.sock \
-v /home/docker/data/jenkins:/var/jenkins_home \
-v /home/docker/data/jenkins/.ssh:/root/.ssh \
-e KNOWN_HOSTS=bitbucket.org \
taypo/jenkins
</code></pre>
<p>This will store image data in <code>/home/docker/data/jenkins</code>directory of the host.</p>
<p>Cheers..</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Dockerizing Your Spring Boot Application]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p><em>Update:<br>
This is an older post. There are now better ways to containerize your java applications such as <a href="https://github.com/GoogleContainerTools/jib">Jib</a> and <a href="https://buildpacks.io/">BuildPack</a>.</em></p>
<hr>
<p>In this post we will be creating a docker container that will run the sample application from the <a href="https://spring.io/guides/gs/spring-boot/">spring boot getting started guide</a>.</p>
<h4 id="checkoutthesample">Checkout the Sample</h4>
<p>We start with</p>]]></description><link>https://www.taypo.com/dockerizing-your-spring-boot-application/</link><guid isPermaLink="false">5e907395fa65d70001e88c41</guid><category><![CDATA[spring-boot]]></category><category><![CDATA[docker]]></category><dc:creator><![CDATA[Bahadır Yağan]]></dc:creator><pubDate>Mon, 16 Nov 2015 22:03:13 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p><em>Update:<br>
This is an older post. There are now better ways to containerize your java applications such as <a href="https://github.com/GoogleContainerTools/jib">Jib</a> and <a href="https://buildpacks.io/">BuildPack</a>.</em></p>
<hr>
<p>In this post we will be creating a docker container that will run the sample application from the <a href="https://spring.io/guides/gs/spring-boot/">spring boot getting started guide</a>.</p>
<h4 id="checkoutthesample">Checkout the Sample</h4>
<p>We start with downloading the source code from github.</p>
<pre><code class="language-language-bash">git clone https://github.com/spring-guides/gs-spring-boot.git
</code></pre>
<p>Change into the project directory, and build it.</p>
<pre><code class="language-language-bash">cd gs-spring-boot/complete/
mvn package
</code></pre>
<p>Now we will create a dockerfile to describe our container image. You can create this file in the project root for now.</p>
<h4 id="dockerfile">Dockerfile</h4>
<pre><code class="language-language-docker">FROM java:8
EXPOSE 8080
CMD java -jar -Djava.security.egd=file:/dev/./urandom gs-spring-boot-0.1.0.jar
ADD target/gs-spring-boot-0.1.0.
</code></pre>
<p>Let's look at each line</p>
<pre><code>FROM java:8
</code></pre>
<p>This tells docker to base this container from the official java container tagged with &quot;8&quot;. More specifically OpenJDK 8. You can check out other options from the <a href="https://hub.docker.com/_/java/">offical java repository</a>.</p>
<pre><code>EXPOSE 8080
</code></pre>
<p>Expose tells docker what network ports the container will be listening at runtime. You can than make this port available to the host or other containers. More common scenario is to use a reverse proxy container, and forward requests coming to a specific domain name to this port. I will cover this in a later post.</p>
<pre><code>CMD java -jar -Djava.security.egd=file:/dev/./urandom gs-spring-boot-0.1.0.jar
</code></pre>
<p>CMD specifies the command that will run when the container is initialized. We just run our spring boot application with a security setting that will speed up tomcat startup.</p>
<pre><code>ADD target/gs-spring-boot-0.1.0.jar .
</code></pre>
<p>This will just add our application jar file inside the container.</p>
<p>Check out the <a href="http://docs.docker.com/engine/reference/builder/">Dockerfile reference</a> for other options.</p>
<h4 id="thecontainer">The Container</h4>
<p>Let's first build the docker container that we just defined.</p>
<pre><code class="language-language-bash">docker build -t spring-boot-docker .
</code></pre>
<p><code>spring-boot-docker</code> is the name that we have given our container. We are going to use this name in future docker commands.</p>
<h4 id="runningitall">Running it All</h4>
<pre><code class="language-language-bash">docker run -p 8080:8080 -t spring-boot-docker
</code></pre>
<p>You can browse to <a href="http://localhost:8080">http://localhost:8080</a> to see it in action.</p>
<blockquote>
<p>Note to OSX and Windows users. docker is not native to your operating system. You are most probably using boot2docker. If so, use the ip address of your docker virtual machine instead of <code>localhost</code></p>
</blockquote>
<!--kg-card-end: markdown-->]]></content:encoded></item></channel></rss>