{"id":246,"date":"2020-08-08T23:48:23","date_gmt":"2020-08-08T23:48:23","guid":{"rendered":"https:\/\/lab.rapternet.us\/?p=246"},"modified":"2020-08-29T22:23:19","modified_gmt":"2020-08-29T22:23:19","slug":"irc-botnet-and-jenkins","status":"publish","type":"post","link":"https:\/\/lab.rapternet.us\/?p=246","title":{"rendered":"IRC Botnet and Jenkins"},"content":{"rendered":"\n<p>I wrote a number of IRC bots a number of years ago, hosting them on my infrastructure. Since building a 3 node docker swarm, I decided that these would be good candidates to use in learning Jenkins for both auto building the software, and building containers. I hadn&#8217;t made my own dockerfiles before, nor had I setup proper builds outside of my IDE for these bots before.<\/p>\n\n\n\n<!--more-->\n\n\n\n<h2 class=\"wp-block-heading\">Dockerfile for Jenkins<\/h2>\n\n\n\n<p>In order for Jenkins to build a docker container, it needs access to docker itself. This can be done by building a custom docker container for Jenkins that has the required dependencies. Since the plan was to use Ant to build the bots as well, this too was included in the Jenkins container. Below is the resulting Dockerfile.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">FROM jenkins\/jenkins:lts\nUSER root\nRUN apt-get update &amp;&amp; \\\napt-get -y install apt-transport-https \\\n    ca-certificates \\\n    curl \\\n    ant \\\n    gnupg2 \\\n    software-properties-common &amp;&amp; \\\ncurl -fsSL https:\/\/download.docker.com\/linux\/$(. \/etc\/os-release; echo \"$ID\")\/gpg &gt; \/tmp\/dkey; apt-key add \/tmp\/dkey &amp;&amp; \\\nadd-apt-repository \\\n    \"deb [arch=amd64] https:\/\/download.docker.com\/linux\/$(. \/etc\/os-release; echo \"$ID\") \\\n    $(lsb_release -cs) \\\n    stable\" &amp;&amp; \\\napt-get update &amp;&amp; \\\napt-get -y install docker-ce\nRUN apt-get install -y docker-ce\nRUN usermod -a -G docker jenkins\nUSER jenkins\n<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Jenkins Plugins for Java\/Docker Pipeline<\/h2>\n\n\n\n<p>On first start of Jenkins, the default plugins were installed for use and the following plugins were added:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Docker Pipeline<ul><li>Auth Tokens API<\/li><li>Docker Commons<\/li><\/ul><\/li><\/ul>\n\n\n\n<p>I didn&#8217;t use any other plugins for my jenkins\/docker pipeline to get everything going.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Docker-Compose for Jenkins<\/h2>\n\n\n\n<p>We needed to deploy Jenkins to the docker swarm cluster. This is a very simple compose file just pointing the cluster at the local build of Jenkins, providing a port to access the web GUI and a location for its data to exist within the gluster filesystem.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">---\nversion: \"3.2\"\n\nservices:\n  jenkins:\n    image: 127.0.0.1:5000\/jenkins\n    ports:\n      - \"8070:8080\"\n      - \"50000:50000\"\n    volumes:\n      - \/mnt\/data\/jenkins:\/var\/jenkins_home\n      - \/var\/run\/docker.sock:\/var\/run\/docker.sock<\/pre>\n\n\n\n<p>One aspect in this compose file is that docker.sock probably not needed since jenkins isn&#8217;t being used to update the docker services itself, though might be worth seeing if it can in a pipeline. This could be additional capability added in the future.<\/p>\n\n\n\n<p>Note: All of the docker-compose files included in this are deployed using docker stack deploy.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Jenkins Rebuilding Jenkins and Reloading<\/h2>\n\n\n\n<p>I created a pipeline to build the Jenkins container from above and push it to the docker registry. Since this dockerfile is a part of a general GIT repo I have, I&#8217;ll need to get to the correct folder in that GIT repo before building. This is about the only interesting part of this Jenkins pipeline.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">pipeline {\n    environment {\n    registry = \"127.0.0.1:5000\/jenkins\"\n  }  \n  agent any  \n  stages {\n      stage('Git Pull') {\n          steps{\n            git 'https:\/\/github.com\/AeroSteveO\/Bash-Scripts.git'\n          }\n      }\n    stage('Building image') {\n      steps{\n          dir(\"${env.WORKSPACE}\/Docker-Compose\/jenkins\"){ \n            script {\n              dockerImage = docker.build registry + \":latest\"\n            }\n          }\n      }\n    }\n  \n    stage('Deploy Image') {\n      steps{\n        script {\n            docker.withRegistry( '' ) {\n              dockerImage.push()\n            }\n          }\n        }\n      }\n  }\n}<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Jenkins Autobuild for Wheatley<\/h2>\n\n\n\n<p>The IRC bot projects were originally managed manually with NetBeans doing the builds, and manually pushing the new jar files to the server. I wanted a generic way to build it without using NetBeans, but still somewhat compatible, so I setup some ant scripts for building it that could be used with Jenkins.<\/p>\n\n\n\n<p>Since Ant is also capable of doing more than just build scripts, we&#8217;ll be using it to run the java applications as well. This at least gives us a single build and run script using Ant.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">&lt;project name=\"Wheatley\" basedir=\".\" default=\"main\"&gt;\n\n\n    &lt;property name=\"src.dir\"     value=\"src\"\/&gt;\n\n    &lt;property name=\"build.dir\"   value=\"build\"\/&gt;\n    &lt;property name=\"classes.dir\" value=\"${build.dir}\/classes\"\/&gt;\n    &lt;property name=\"jar.dir\"     value=\"${build.dir}\/jar\"\/&gt;\n\n    &lt;property name=\"main-class\"  value=\"rapternet.irc.bots.wheatley.listeners.WheatleyMain\"\/&gt;\n    &lt;property name=\"lib.dir\"     value=\"lib\"\/&gt;\n\n    &lt;path id=\"classpath\"&gt;\n        &lt;fileset dir=\"${lib.dir}\" includes=\"**\/*.jar\"\/&gt;\n    &lt;\/path&gt;\n\n\n    &lt;target name=\"clean\"&gt;\n        &lt;delete dir=\"${build.dir}\"\/&gt;\n    &lt;\/target&gt;\n\n    &lt;target name=\"compile\"&gt;\n        &lt;mkdir dir=\"${classes.dir}\"\/&gt;\n        &lt;javac srcdir=\"${src.dir}\" destdir=\"${classes.dir}\" classpathref=\"classpath\"\/&gt;\n    &lt;\/target&gt;\n\n    &lt;target name=\"jar\" depends=\"compile\"&gt;\n        &lt;mkdir dir=\"${jar.dir}\"\/&gt;\n        &lt;jar destfile=\"${jar.dir}\/${ant.project.name}.jar\" basedir=\"${classes.dir}\"&gt;\n            &lt;manifest&gt;\n                &lt;attribute name=\"Main-Class\" value=\"${main-class}\"\/&gt;\n            &lt;\/manifest&gt;\n        &lt;\/jar&gt;\n    &lt;\/target&gt;\n\n    &lt;target name=\"run\" depends=\"jar\"&gt;\n        &lt;java fork=\"true\" classname=\"${main-class}\"&gt;\n            &lt;classpath&gt;\n                &lt;path refid=\"classpath\"\/&gt;\n                &lt;path location=\"${jar.dir}\/${ant.project.name}.jar\"\/&gt;\n            &lt;\/classpath&gt;\n\t&lt;\/java&gt;\n    &lt;\/target&gt;\n\n    &lt;target name=\"clean-build\" depends=\"clean,jar\"\/&gt;\n\n    &lt;target name=\"main\" depends=\"clean,run\"\/&gt;\n&lt;\/project&gt;<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Jenkins Docker Container Build for Wheatley<\/h2>\n\n\n\n<p>After getting my projects to run with a general build script, I needed to work on a way to build a docker container for them. This was done with a simple base of using OpenJDK 8, copying in my libraries and source, and building everything.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">FROM openjdk:8-alpine\n\nRUN apk add --no-cache apache-ant\n\nCOPY . \/usr\/src\/wheatley\nWORKDIR \/usr\/src\/wheatley\nRUN ant clean-build\nCMD [\"ant\", \"run\"]<\/pre>\n\n\n\n<p>The pipeline to do the Jenkins build is simple enough, it performs a git pull, runs docker build, and then pushes that container into the registry.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">pipeline {\nenvironment {\nregistry = \"127.0.0.1:5000\/wheatley\"\n}\nagent any\nstages {\nstage('Git Pull') {\nsteps{\ngit 'https:\/\/github.com\/AeroSteveO\/Wheatley.git'\n}\n}\nstage('Building image') {\nsteps{\nscript {\ndockerImage = docker.build registry + \":latest\"\n}\n}\n}\n<code>stage('Deploy Image') { steps{ script { docker.withRegistry( '' ) { dockerImage.push() } } } }<\/code>\n}\n}<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Updating Code for use with Docker<\/h2>\n\n\n\n<p>The IRC bots were simple enough to update for running inside a docker container. When they were originally written, all of the input files were referenced from the directory the bots were running from. So step 1 of updating the code for docker was to provide a default path for the configuration files to be found at, and a way to tell them what that path was. This was done by using an environment variable to provide the path for the configurations to be stored at. Additional environment variables were added to provide a way to get defaults into the bot on first run before the configuration files are all populated.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Docker Compose for the BotNet<\/h2>\n\n\n\n<p>Once the containers are being auto-built and sent to the registry, we need to start them up and provide for auto-updating. For docker-swarm, we can use <a href=\"https:\/\/github.com\/djmaze\/shepherd\">shepherd<\/a> as the auto update service. Depending on the setup, we could use other services too<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><a href=\"https:\/\/github.com\/djmaze\/shepherd\">Shepherd<\/a>: Docker Swarm Update Service<\/li><li><a href=\"https:\/\/github.com\/containrrr\/watchtower\">WatchTower<\/a>: Single node docker update service<\/li><\/ul>\n\n\n\n<pre class=\"wp-block-preformatted\">---\nversion: \"3.2\"\n\nservices:\n  wheatley:\n    image: 127.0.0.1:5000\/wheatley\n    environment:\n      BOT_CONFIG_FOLDER: \/config\/\n    volumes:\n      - \/mnt\/data\/wheatley:\/config\n\n  triviabot:\n    image: 127.0.0.1:5000\/triviabot\n    environment:\n      BOT_CONFIG_FOLDER: \/config\/\n    volumes:\n      - \/mnt\/data\/wheatley:\/config\n\n  shepherd:\n    build: .\n    image: mazzolino\/shepherd\n    environment:\n      TZ: 'US\/Eastern'\n      SLEEP_TIME: '5m'\n      FILTER_SERVICES: ''\n      VERBOSE: 'true'\n      BLACKLIST_SERVICES: 'znc znc_znc'\n    volumes:\n      - \/var\/run\/docker.sock:\/var\/run\/docker.sock\n    deploy:\n      placement:\n        constraints:\n        - node.role == manager<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n\n\n\n<p>The project was mostly a success. I have the two IRC bots I wrote auto building with Jenkins, deploying to my docker swarm cluster and starting up. This makes it much easier to deploy new versions rather than SCPing a new jar file to the server, killing the process and restarting it. The one aspect that isn&#8217;t working quite as expected is shepherd, it took a bit of configuration to keep it from trying to upgrade all containers on the swarm (focusing only on the locally created containers first). The log file shows that shepherd is running into issues when dealing with the local docker registry. This can be taken care of later, as we have the build working.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I wrote a number of IRC bots a number of years ago, hosting them on my infrastructure. Since building a 3 node docker swarm, I decided that these would be good candidates to use in learning Jenkins for both auto building the software, and building containers. I hadn&#8217;t made my own dockerfiles before, nor had &hellip; <\/p>\n<p class=\"link-more\"><a href=\"https:\/\/lab.rapternet.us\/?p=246\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;IRC Botnet and Jenkins&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4],"tags":[17,16,13,40],"class_list":["post-246","post","type-post","status-publish","format-standard","hentry","category-how-to","tag-ci-cd","tag-development","tag-docker","tag-jenkins"],"_links":{"self":[{"href":"https:\/\/lab.rapternet.us\/index.php?rest_route=\/wp\/v2\/posts\/246","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/lab.rapternet.us\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/lab.rapternet.us\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/lab.rapternet.us\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/lab.rapternet.us\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=246"}],"version-history":[{"count":5,"href":"https:\/\/lab.rapternet.us\/index.php?rest_route=\/wp\/v2\/posts\/246\/revisions"}],"predecessor-version":[{"id":350,"href":"https:\/\/lab.rapternet.us\/index.php?rest_route=\/wp\/v2\/posts\/246\/revisions\/350"}],"wp:attachment":[{"href":"https:\/\/lab.rapternet.us\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=246"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/lab.rapternet.us\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=246"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/lab.rapternet.us\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=246"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}