<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	
	xmlns:georss="http://www.georss.org/georss"
	xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#"
	>

<channel>
	<title>nordri&#039;s Blog</title>
	<atom:link href="http://www.muspells.net/blog/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.muspells.net/blog</link>
	<description>We&#039;re working on it...</description>
	<lastBuildDate>Sun, 15 Mar 2020 19:03:35 +0000</lastBuildDate>
	<language>en-GB</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.2.2</generator>
<site xmlns="com-wordpress:feed-additions:1">9740989</site>	<item>
		<title>ETCD Backup and Restore</title>
		<link>https://www.muspells.net/blog/2020/03/etcd-backup-and-restore/</link>
		
		<dc:creator><![CDATA[Fede Diaz]]></dc:creator>
		<pubDate>Sun, 15 Mar 2020 19:03:35 +0000</pubDate>
				<category><![CDATA[Kubernetes]]></category>
		<category><![CDATA[backup]]></category>
		<category><![CDATA[etcd]]></category>
		<category><![CDATA[kubernetes]]></category>
		<category><![CDATA[minikube]]></category>
		<guid isPermaLink="false">https://www.muspells.net/blog/?p=1793</guid>

					<description><![CDATA[In this post we&#8217;ll see how to perform a backup of the ETCD server and how to restore it afterwards. We are working with Minikube. First of all, lets see the how ETCD is configured looking at the manifest file &#8230; <a href="https://www.muspells.net/blog/2020/03/etcd-backup-and-restore/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
										<content:encoded><![CDATA[
<p>In this post we&#8217;ll see how to perform a backup of the ETCD server and how to restore it afterwards. We are working with Minikube.</p>



<p>First of all, lets see the how ETCD is configured looking at the manifest file  <code>/etc/kubernetes/etcd</code>/manifests/etcd.yaml</p>



<pre class="wp-block-code"><code>...
spec:
  containers:
  - command:
    - etcd
    - --advertise-client-urls=https://192.168.99.100:2379
    - --cert-file=/var/lib/minikube/certs/etcd/server.crt
    - --client-cert-auth=true
    - --data-dir=/var/lib/minikube/etcd
    - --initial-advertise-peer-urls=https://192.168.99.100:2380
    - --initial-cluster=minikube=https://192.168.99.100:2380
    - --key-file=/var/lib/minikube/certs/etcd/server.key
    - --listen-client-urls=https://127.0.0.1:2379,https://192.168.99.100:2379
    - --listen-metrics-urls=http://127.0.0.1:2381
    - --listen-peer-urls=https://192.168.99.100:2380
    - --name=minikube
    - --peer-cert-file=/var/lib/minikube/certs/etcd/peer.crt
    - --peer-client-cert-auth=true
    - --peer-key-file=/var/lib/minikube/certs/etcd/peer.key
    - --peer-trusted-ca-file=/var/lib/minikube/certs/etcd/ca.crt
    - --snapshot-count=10000
    - --trusted-ca-file=/var/lib/minikube/certs/etcd/ca.crt
...</code></pre>



<p>We need the following information:</p>



<ol><li>advertise-client-urls</li><li>cert-file</li><li>key-file</li><li>trusted-ca-file</li></ol>



<p>Get those certificates files and store in a local folder and try to connect to ETCD to see the members list:</p>



<pre class="wp-block-code"><code>$ export WORKDIR=${PWD}
$ ETCDCTL_API=3 etcdctl member list \
  --cacert=${WORKDIR}/ca.crt \
  --cert=${WORKDIR}/server.crt \
  --key=${WORKDIR}/server.key \
  --endpoints=https://192.168.99.100:2379
5d05948eea4c8c0a, started, minikube, https://192.168.99.100:2379, https://192.168.99.100:2379
</code></pre>



<p>It&#8217;s important to have something deployed on the cluster, if not, run this commands to create a couple of deployments:</p>



<pre class="wp-block-code"><code>$ kubectl run nginx --image nginx --replicas 3
$ kubectl run redis --image redis --replicas 2 </code></pre>



<p>After that we&#8217;ll have two apps up and running</p>



<pre class="wp-block-code"><code>$ kubectl get all
NAME                         READY   STATUS    RESTARTS   AGE
pod/nginx-6db489d4b7-c8qjt   1/1     Running   0          54m
pod/nginx-6db489d4b7-cstbc   1/1     Running   0          54m
pod/nginx-6db489d4b7-dtpc2   1/1     Running   0          54m
pod/redis-5c7c978f78-mzjc4   1/1     Running   0          54m
pod/redis-5c7c978f78-svs5v   1/1     Running   0          54m

NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
service/kubernetes   ClusterIP   10.96.0.1    &lt;none>        443/TCP   29d

NAME                    READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/nginx   3/3     3            3           54m
deployment.apps/redis   2/2     2            2           54m

NAME                               DESIRED   CURRENT   READY   AGE
replicaset.apps/nginx-6db489d4b7   3         3         3       54m
replicaset.apps/redis-5c7c978f78   2         2         2       54m
</code></pre>



<p>Perform the backup by executing:</p>



<pre class="wp-block-code"><code>$ ETCDCTL_API=3 etcdctl snapshot save \
  --cacert=${WORKDIR}/ca.crt \
  --cert=${WORKDIR}/server.crt \
  --key=${WORKDIR}/server.key \
  --endpoints=https://192.168.99.100:2379
  ${WORKDIR}/my-backup.db</code></pre>



<p>This command will save a copy of the ETCD database in <code>my-backup.db</code> file.</p>



<p>Now, we can destroy the apps we deployed in the step before:</p>



<pre class="wp-block-code"><code>$ kubectl delete deployment nginx redis</code></pre>



<p>Let&#8217;s restore the database</p>



<pre class="wp-block-code"><code>ETCDCTL_API=3 etcdctl snapshot restore \
  --cacert=${WORKDIR}/ca.crt \
  --cert=${WORKDIR}/server.crt \
  --key=${WORKDIR}/server.key \
  --endpoints=https://192.168.99.100:2379 \
  ${WORKDIR}/my-backup.db \
  --initial-cluster="minikube=https://192.168.99.100:2379" \
  --initial-cluster-token="etcd-cluster-1" \
  --initial-advertise-peer-urls="https://192.168.99.100:2379" \
  --name="minikube" \
  --data-dir="${WORKDIR}/etcd-restore"</code></pre>



<p>Here we use values we got from the ETCD manifest file like the IPs and name and we add the initial token for the initial bootstrap and the data-dir where we&#8217;re gonna restore the database. This folder is local, so we&#8217;ll have to copy this folder to minikube afterwards. You can use SSH for example. I&#8217;m using <code>/var/lib/minikube/etcd-restore</code> to keep this files.</p>



<p>Once we have the database restored we need to tell Kubernetes to read the restored one, to do that, we edit the ETCD manifest file:</p>



<pre class="wp-block-code"><code>...
spec:
  containers:
  - command:
    - etcd
    - --advertise-client-urls=https://192.168.99.100:2379
    - --cert-file=/var/lib/minikube/certs/etcd/server.crt
    - --client-cert-auth=true
    - --data-dir=/var/lib/minikube/etcd-restore
    - --initial-advertise-peer-urls=https://192.168.99.100:2380
    - --initial-cluster=minikube=https://192.168.99.100:2380
    - --key-file=/var/lib/minikube/certs/etcd/server.key
    - --listen-client-urls=https://127.0.0.1:2379,https://192.168.99.100:2379
    - --listen-metrics-urls=http://127.0.0.1:2381
    - --listen-peer-urls=https://192.168.99.100:2380
    - --name=minikube
    - --peer-cert-file=/var/lib/minikube/certs/etcd/peer.crt
    - --peer-client-cert-auth=true
    - --peer-key-file=/var/lib/minikube/certs/etcd/peer.key
    - --peer-trusted-ca-file=/var/lib/minikube/certs/etcd/ca.crt
    - --snapshot-count=10000
    - --trusted-ca-file=/var/lib/minikube/certs/etcd/ca.crt
    - --initial-cluster-token=etcd-cluster-1
...
    volumeMounts:
    - mountPath: /var/lib/minikube/etcd-restore
      name: etcd-data
    - mountPath: /var/lib/minikube/certs/etcd
      name: etcd-certs
  hostNetwork: true
  priorityClassName: system-cluster-critical
  volumes:
  - hostPath:
      path: /var/lib/minikube/certs/etcd
      type: DirectoryOrCreate
    name: etcd-certs
  - hostPath:
      path: /var/lib/minikube/etcd-restore
      type: DirectoryOrCreate
    name: etcd-data

</code></pre>



<p>We need to change <strong>initial-cluster-token</strong> with the token we&#8217;ve choose before and <strong>data-dir</strong> to point to the folder we use to keep ETCD files. Then change this PATH also in the <strong>volumes</strong> and <strong>volumeMounts</strong> sections.</p>



<p>You can now check that everything is now restored if you run <code>kubectl</code> but restart <code>kube-apiserver</code> is needed, from minikube:</p>



<pre class="wp-block-code"><code>$ docker ps | grep kube-apiserver
8255c0e35e0f        41ef50a5f06a           "kube-apiserver --ad…"   3 hours ago         Up 3 hours                              k8s_kube-apiserver_kube-apiserver-minikube_kube-system_bcfa63252833e5b041a29d7485a74d90_3
$ docker rm -f 8255c0e35e0f</code></pre>



<p>We&#8217;ll have some downtime at this point, but if we&#8217;re restoring a backup is probably because some disaster happened.</p>
]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1793</post-id>	</item>
		<item>
		<title>Docker Image Scanner for Vulnerabilities With Clair</title>
		<link>https://www.muspells.net/blog/2019/05/docker-image-scanner-for-vulnerabilities-with-clair/</link>
		
		<dc:creator><![CDATA[Fede Diaz]]></dc:creator>
		<pubDate>Wed, 15 May 2019 15:40:53 +0000</pubDate>
				<category><![CDATA[Docker]]></category>
		<category><![CDATA[Jenkins]]></category>
		<category><![CDATA[Seguridad]]></category>
		<category><![CDATA[clair]]></category>
		<category><![CDATA[docker]]></category>
		<category><![CDATA[security scanner]]></category>
		<category><![CDATA[vulnerability]]></category>
		<guid isPermaLink="false">https://www.muspells.net/blog/?p=1751</guid>

					<description><![CDATA[I’m gonna tell you how you can add a step in your CI pipeline to check if the Docker image you’re build contains vulnerabilities or not. Pre-requisites I assume you’ve Docker installed on your system. We&#8217;re gonna use Jenkins but &#8230; <a href="https://www.muspells.net/blog/2019/05/docker-image-scanner-for-vulnerabilities-with-clair/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
										<content:encoded><![CDATA[
<p>I’m gonna tell you how you can add a step in your CI pipeline to check if the Docker image you’re build contains vulnerabilities or not.</p>



<h3 class="wp-block-heading">Pre-requisites</h3>



<p>I assume you’ve Docker installed on your system. We&#8217;re gonna use Jenkins but is optional.</p>



<h3 class="wp-block-heading">Clair</h3>



<p><a href="https://coreos.com/clair/docs/latest/" rel="noreferrer noopener" target="_blank">Clair</a> is an open source project for the static analysis of vulnerabilities in <a href="https://github.com/appc/spec" rel="noreferrer noopener" target="_blank">appc</a> and <a href="https://github.com/docker/docker/blob/master/image/spec/v1.md" rel="noreferrer noopener" target="_blank">docker</a> containers. It’s been developed by CoreOS.</p>



<h3 class="wp-block-heading">Vulnerabilities Database</h3>



<p>Clair relay on Postgres to keep the database. We’ve two different options here. We can create a new Postgres database which will be initializes when Clair starts or we can use a database already provisioned.&nbsp;</p>



<p>If you want to try the first option keep in mind it takes a while to feed the database (10~15 minutes depends on network).</p>



<p>We’re using the second option here. Go to a terminal and run this command:</p>



<pre class="wp-block-code"><code>$ docker network create ci
$ docker volume create --name clair-postgres
$ docker run --detach \
   --name clair-postgres \
   --publish 5432:5432 \
   --net ci \
   --volume clair-postgres:/var/lib/postgresql/data \
   arminc/clair-db:latest</code></pre>



<p>We just have created a new network to Clair can resolve the database by its name, a volume and a Docker container. After a couple seconds we can check the database is up and ready.</p>



<pre class="wp-block-code"><code>$ docker logs --tail 1 clair-postgres 
2019-05-15 13:36:00.068 UTC [1] LOG:  database system is ready to accept connections</code></pre>



<h3 class="wp-block-heading">Clair Service</h3>



<p>Now it&#8217;s time to run the service. But first, a little configuration is needed. We must set the database for Clair in the config file. Run the following command:</p>



<pre class="wp-block-code"><code>$ curl --silent https://raw.githubusercontent.com/nordri/config-files/master/clair/config-clair.yaml | sed "s/POSTGRES_NAME/clair-postgres/" > config.yaml</code></pre>



<p>We&#8217;re changing the string <em>POSTGRES_NAME </em>by <em>clair-postgres</em> which is the name we&#8217;ve gave to the Postgres container. Now, we can launch the Clair container by running:</p>



<pre class="wp-block-code"><code>$ docker run --detach \
  --name clair \
  --net ci \
  --publish 6060:6060 \
  --publish 6061:6061 \
  --volume ${PWD}/config.yaml:/config/config.yaml \
  quay.io/coreos/clair:latest -config /config/config.yaml</code></pre>



<p>And that is.</p>



<h3 class="wp-block-heading">Launch an scanner</h3>



<p>It&#8217;s time to check everything is working properly. To run the Clair scanner I&#8217;ve just built a container with the latest release. You can found it <a href="https://github.com/arminc/clair-scanner/releases">here</a> and then build the image using this Dockerfile.</p>



<pre class="wp-block-code"><code>FROM debian:jessie

COPY clair-scanner_linux_amd64 /clair-scanner
RUN chmod +x /clair-scanner</code></pre>



<p>I already did so you can use this image: <code>nordri/clair-scanner</code>. </p>



<p>Let&#8217;s check some images now. One of Clair limitations is it cannot scan remote images. All images must be locals. To scan an image just launch</p>



<pre class="wp-block-code"><code>$ docker run -ti \
  --rm \
  --name clair-scanner \
  --net ci \
  -v /var/run/docker.sock:/var/run/docker.sock \
  nordri/clair-scanner:latest /bin/bash</code></pre>



<p>Now we&#8217;re inside the container and we&#8217;re able to launch the scanner:</p>



<pre class="wp-block-code"><code># export IP=$(ip r | tail -n1 | awk '{ print $9 }')
# /clair-scanner --ip ${IP} --clair=http://clair:6060 debian:jessie</code></pre>



<p>If we launch that as it, we&#8217;ll see an endless list of vulnerabilities, which is more noise than something useful. So, we can filter by severity using this flag:</p>



<pre class="wp-block-code"><code>-t, --threshold="Unknown"             CVE severity threshold. Valid values; 'Defcon1', 'Critical', 'High', 'Medium', 'Low', 'Negligible', 'Unknown'</code></pre>



<p>We can choose only check for <strong>critical</strong> or higher and then the list will be much more gentle because all the vulnerabilities will be treat as <strong>approved</strong>, and, which is much more interested, the command will exit with 0. Then we can add this to a CI pipeline.</p>



<h3 class="wp-block-heading">Jenkins Integration</h3>



<p>If you&#8217;ve Jenkins running in your infrastructure, you&#8217;ll be probably interested in check the images you&#8217;re delivering to your customers. </p>



<p>This simple Jenkinsfile can solve the problem</p>



<pre class="wp-block-code"><code>node {

   docker.image('docker').inside('-v /var/run/docker.sock:/var/run/docker.sock') {
      
       stage ('Checkout') {
         checkout scm
       }

       stage ('Build Docker image') {
           // Build docker image
           // docker build... DOCKER_IMAGE
       }
   }

   docker.image('nordri/clair-scanner').inside('--net ci') {

       stage ('Security scanner') {
           sh '''
             IP=$(ip r | tail -n1 | awk '{ print $9 }')
             /clair-scanner --ip ${IP} --clair=http://clair:6060 --threshold="Critical" DOCKER_IMAGE
           '''
       }
   }
}</code></pre>



<p>As we can see, we&#8217;re using a container to build the image and another one to scan that image for vulnerabilities, we set the threshold to Critical so only really big problem will made the pipeline to fail.</p>



<h4 class="wp-block-heading">References</h4>



<ul><li><a href="https://github.com/coreos/clair">https://github.com/coreos/clair</a></li><li><a href="https://github.com/arminc/clair-scanner"></a><a href="https://github.com/arminc/clair-scanner">https://github.com/arminc/clair-scanner</a></li><li><a href="https://github.com/arminc/clair-local-scan">https://github.com/arminc/clair-local-scan</a></li></ul>



<p></p>
]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1751</post-id>	</item>
		<item>
		<title>Recovering Untagged Images From ECR</title>
		<link>https://www.muspells.net/blog/2019/04/recovering-untagged-images-from-ecr/</link>
		
		<dc:creator><![CDATA[Fede Diaz]]></dc:creator>
		<pubDate>Fri, 26 Apr 2019 15:50:11 +0000</pubDate>
				<category><![CDATA[AWS]]></category>
		<category><![CDATA[Docker]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[aws]]></category>
		<category><![CDATA[docker]]></category>
		<category><![CDATA[ecr]]></category>
		<guid isPermaLink="false">https://www.muspells.net/blog/?p=1739</guid>

					<description><![CDATA[Happened today that our CI system created a new Docker Image with a tag that was supposed to be used in production. So, we faced with a Docker Image tagged like the production one but it wasn&#8217;t the production one &#8230; <a href="https://www.muspells.net/blog/2019/04/recovering-untagged-images-from-ecr/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
										<content:encoded><![CDATA[
<p>Happened today that our CI system created a new Docker Image with a tag that was supposed to be used in production. So, we faced with a Docker Image tagged like the production one but it wasn&#8217;t the production one at all and, on the other hand, the Docker Image from production was there untagged. What should we do?</p>



<p>Actually, the process is quite simple if you know how to cope with that. First we have to log into the ECR Service.</p>



<pre class="wp-block-code"><code>$ $(aws ecr get-login --no-include-email --region eu-west-1)

Login Succeeded
</code></pre>



<p>Then locate the <em>sha256</em> and download the manifest.</p>



<pre class="wp-block-code"><code>$ MANIFEST=$(aws ecr batch-get-image --repository-name sandbox --image-ids imageDigest=sha256:e226e9aaa12beb32bfe65c571cb60605b2de13338866bc832bba0e39f6819365 --query 'images[].imageManifest' --output text)</code></pre>



<p>You can find the <em>sha256</em> in the Image list, copy and paste the one belongs to the untagged image.</p>



<figure class="wp-block-image"><img decoding="async" width="1013" height="95" src="https://www.muspells.net/blog/wp-content/uploads/2019/04/008_Selección.png" alt="" class="wp-image-1744" srcset="https://www.muspells.net/blog/wp-content/uploads/2019/04/008_Selección.png 1013w, https://www.muspells.net/blog/wp-content/uploads/2019/04/008_Selección-300x28.png 300w, https://www.muspells.net/blog/wp-content/uploads/2019/04/008_Selección-768x72.png 768w" sizes="(max-width: 1013px) 100vw, 1013px" /></figure>



<p>The manifest is basically all the layers which conform the Docker Image.</p>



<p>Then tag the image</p>



<pre class="wp-block-code"><code>$ aws ecr put-image --repository-name sandbox --image-tag backup --image-manifest "$MANIFEST"</code></pre>



<p>Now, you are able to pull the new tagged image</p>



<pre class="wp-block-code"><code>docker pull myarn.amazonaws.com/sandbox:backup</code></pre>



<p><strong>Reference:</strong></p>



<ul><li><a href="https://stackoverflow.com/questions/53198759/how-to-download-or-tag-an-untagged-image-on-ecr">https://stackoverflow.com/questions/53198759/how-to-download-or-tag-an-untagged-image-on-ecr</a></li></ul>
]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1739</post-id>	</item>
		<item>
		<title>Azure Batch: Task in Containers</title>
		<link>https://www.muspells.net/blog/2018/11/azure-batch-task-in-containers/</link>
		
		<dc:creator><![CDATA[Fede Diaz]]></dc:creator>
		<pubDate>Sat, 10 Nov 2018 16:32:31 +0000</pubDate>
				<category><![CDATA[Azure]]></category>
		<category><![CDATA[Microsoft]]></category>
		<category><![CDATA[azure]]></category>
		<category><![CDATA[batch]]></category>
		<category><![CDATA[docker]]></category>
		<category><![CDATA[microsoft]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[registry]]></category>
		<guid isPermaLink="false">https://www.muspells.net/blog/?p=1706</guid>

					<description><![CDATA[In today&#8217;s post I&#8217;ll be talking about how to send tasks to Microsoft Azure Batch able to run in containers. The task I want to solve in this example is calculating whether a number is prime or not. This Python &#8230; <a href="https://www.muspells.net/blog/2018/11/azure-batch-task-in-containers/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
										<content:encoded><![CDATA[<p>In today&#8217;s post I&#8217;ll be talking about how to send tasks to Microsoft Azure Batch able to run in containers. The task I want to solve in this example is calculating whether a number is prime or not. <a href="https://github.com/nordri/microsoft-azure/blob/master/batch-containers/is_prime.py" rel="noopener" target="_blank">This Python</a> code does the work for us. Then, I&#8217;ve write a Dockerfile adding the piece of code to the image. Now, we&#8217;re able to run the script from a Docker container.</p>
<p>Let&#8217;s move forward to Azure Batch, you need to create a Docker registry where you&#8217;ll push the Docker image and an Azure Batch account.</p>
<h1>Docker Registry</h1>
<p>Login into your Azure account and move to <strong>All resources</strong>, click <strong>Add</strong> and look for <strong>Container Registry</strong>. Then click in <strong>Create</strong>. Fill up the information with the name of the registry, the resource group, choose a location closer to you, enable <em>Admin user</em> to be able to push to the repo and the SKU (choose standard here).</p>
<p>Then <strong>Create</strong></p>
<p>In a few seconds the registry will be ready. So go to the Dashboard and click on the registry name (the one you chose before). Click in Settings -> Access keys. Here are the credentials you&#8217;ll need to manage the registry.</p>
<h1>Batch Account</h1>
<p>From the <strong>All resources</strong> look for <strong>Batch service</strong>. Fill up the information with the Account name and Location, Subscription and Resource group should be ready.</p>
<p>Click Review + create and then Create. In a few seconds the service should be ready.</p>
<h1>Building the Container</h1>
<p>Clone the repo</p>
<pre>
git clone https://github.com/nordri/microsoft-azure
</pre>
<p>and build and push the container</p>
<pre>
cd batch-containers
docker build -t YOUR_REGISTRY_SERVER/YOUR_REGISTRY_NAME/YOUR_IMAGE_NAME .
# for example:
docker build -t pythonrepo.azurecr.io/pythonrepo/is_prime:latest .
# Check the image works:
docker run -ti --rm pythonrepo.azurecr.io/pythonrepo/is_prime python is_prime.py 7856
The number: 7856 is not prime
docker run -ti --rm pythonrepo.azurecr.io/pythonrepo/is_prime python is_prime.py 2237
The number: 2237 is prime
# login first
docker login pythonrepo.azurecr.io
Username: pythonrepo
Password: 
# Push
docker push pythonrepo.azurecr.io/pythonrepo/is_prime
</pre>
<h1>Azure Batch</h1>
<p>Now it&#8217;s time to send the task to Azure Batch. To do this, I&#8217;ve worked over <a href="https://github.com/Azure-Samples/batch-python-quickstart/blob/master/src/python_quickstart_client.py" rel="noopener" target="_blank">this Python script</a>. This script creates a pool, a job and three tasks to upload files to Azure Storage. So, I&#8217;ve made some modifications to fit it to my needs.</p>
<h2>Creating the Pool</h2>
<p>I need my pool to be created using instances able to run containers</p>
<pre>
...
def create_pool(batch_service_client, pool_id):
    print('Creating pool [{}]...'.format(pool_id))

    image_ref_to_use = batch.models.ImageReference(
        publisher='microsoft-azure-batch',
        offer='ubuntu-server-container',
        sku='16-04-lts',
        version='latest'
    )

    # Specify a container registry
    # We got the credentials from config.py
    containerRegistry = batchmodels.ContainerRegistry(
        user_name=config._REGISTRY_USER_NAME, 
        password=config._REGISTRY_PASSWORD, 
        registry_server=config._REGISTRY_SERVER
    )

    # The instance will pull the images defined here
    container_conf = batchmodels.ContainerConfiguration(
        container_image_names=[config._DOCKER_IMAGE],
        container_registries=[containerRegistry]
    )

    new_pool = batch.models.PoolAddParameter(
        id=pool_id,
        virtual_machine_configuration=batchmodels.VirtualMachineConfiguration(
            image_reference=image_ref_to_use,
            container_configuration=container_conf,
            node_agent_sku_id='batch.node.ubuntu 16.04'),
        vm_size='STANDARD_A2',
        target_dedicated_nodes=1
    )

    batch_service_client.pool.add(new_pool)
...
</pre>
<p>The key is the <em>ImageReference</em> where we set the instances to run with an OS able to run Docker. You must set the registry credentials and the default Docker image that will be pulled when the instance boots.</p>
<h2>Creating the Task</h2>
<p>I&#8217;ve also changed the Task for the same reason. This task is ready to launch a container in the instance.</p>
<pre>
...
def add_tasks(batch_service_client, job_id, task_id, number_to_test):
    print('Adding tasks to job [{}]...'.format(job_id))

    # This is the user who run the command inside the container.
    # An unprivileged one
    user = batchmodels.AutoUserSpecification(
        scope=batchmodels.AutoUserScope.task,
        elevation_level=batchmodels.ElevationLevel.non_admin
    )

    # This is the docker image we want to run
    task_container_settings = batchmodels.TaskContainerSettings(
        image_name=config._DOCKER_IMAGE,
        container_run_options='--rm'
    )
    
    # The container needs this argument to be executed
    task = batchmodels.TaskAddParameter(
        id=task_id,
        command_line='python /is_prime.py ' + str(number_to_test),
        container_settings=task_container_settings,
        user_identity=batchmodels.UserIdentity(auto_user=user)
    )

    batch_service_client.task.add(job_id, task)
...
</pre>
<p>You can see how I&#8217;ve defined the user inside the container as a non admin user. The Docker image we want to use and the arguments we need to pass in the command line, remember we launch the container like:</p>
<pre>
docker ... imagename python /is_prime.py number
</pre>
<h1>Launching the Script</h1>
<h2>Configure</h2>
<p>In order to launch the script we need to fill up some configuration. Open the <em>config.py</em> file and write all the credentials needed. Remember, all the credentials are in the <strong>Access keys</strong> section.</p>
<h2>Installing Dependencies</h2>
<p>You need Azure Python SDK installed to run the script.</p>
<pre>
pip install -r requirements.txt
</pre>
<h2>Let&#8217;s go</h2>
<p>Now we&#8217;re ready to launch the script:</p>
<pre>
python batch_containers.py 89
Sample start: 2018-11-10 10:11:11

Creating pool [ContainersPool]...
No handlers could be found for logger "msrest.pipeline.requests"
Creating job [ContainersJob]...
Adding tasks to job [ContainersJob]...
Monitoring all tasks for 'Completed' state, timeout in 0:30:00.....................................................................................................................................................................
  Success! All tasks reached the 'Completed' state within the specified timeout period.
Printing task output...
Task: ContainersTask
Standard output:
The number: 89 is prime

Standard error:


Sample end: 2018-11-10 10:14:31
Elapsed time: 0:03:20

Delete job? [Y/n] y
Delete pool? [Y/n] y

Press ENTER to exit...
</pre>
<p>If there&#8217;s a problem with the script we&#8217;ll see the error on <em>stderr.txt</em>.</p>
<pre>
Sample start: 2018-11-10 11:29:56

Creating pool [ContainersPool]...
No handlers could be found for logger "msrest.pipeline.requests"
Creating job [ContainersJob]...
Adding tasks to job [ContainersJob]...
Monitoring all tasks for 'Completed' state, timeout in 0:30:00..................................................................................................................................................................
  Success! All tasks reached the 'Completed' state within the specified timeout period.
Printing task output...
Task: ContainersTask
Standard output:

Standard error:
usage: is_prime.py [-h] number
is_prime.py: error: argument number: invalid int value: 'o'


Sample end: 2018-11-10 11:33:10
Elapsed time: 0:03:14

Delete job? [Y/n] y
yDelete pool? [Y/n] y

Press ENTER to exit...
</pre>
<p>Remember at the end to eliminate resources so that they do not infringe costs.</p>
<h1>References</h1>
<p><a href="https://github.com/Azure-Samples/batch-python-quickstart" rel="noopener" target="_blank">batch-python-quickstart</a><br />
<a href="https://docs.microsoft.com/en-us/azure/batch/batch-docker-container-workloads" rel="noopener" target="_blank">Run container applications on Azure Batch</a></p>
]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1706</post-id>	</item>
		<item>
		<title>Kubernetes Pipeline</title>
		<link>https://www.muspells.net/blog/2018/09/kubernetes-pipeline/</link>
		
		<dc:creator><![CDATA[Fede Diaz]]></dc:creator>
		<pubDate>Fri, 28 Sep 2018 14:50:13 +0000</pubDate>
				<category><![CDATA[Jenkins]]></category>
		<category><![CDATA[Kubernetes]]></category>
		<category><![CDATA[jenkins]]></category>
		<category><![CDATA[kubernetes]]></category>
		<category><![CDATA[maven]]></category>
		<category><![CDATA[minikube]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[springboot]]></category>
		<guid isPermaLink="false">https://www.muspells.net/blog/?p=1686</guid>

					<description><![CDATA[Let&#8217;s explain an easy way to build an integration pipeline (CI) on Minikube. Launch Minikube If you don&#8217;t have Minikube running on your system, $ minikube start --memory 4000 --cpus 2 Wait for a few minutes, you&#8217;ll see something like. &#8230; <a href="https://www.muspells.net/blog/2018/09/kubernetes-pipeline/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
										<content:encoded><![CDATA[<p>Let&#8217;s explain an easy way to build an integration pipeline (CI) on Minikube.</p>
<h1>Launch Minikube</h1>
<p>If you don&#8217;t have Minikube running on your system,</p>
<pre>$ minikube start --memory 4000 --cpus 2</pre>
<p>Wait for a few minutes, you&#8217;ll see something like.</p>
<pre>
Starting local Kubernetes v1.10.0 cluster...
Starting VM...
Getting VM IP address...
Moving files into cluster...
Setting up certs...
Connecting to cluster...
Setting up kubeconfig...
Starting cluster components...
Kubectl is now configured to use the cluster.
Loading cached images from config file.
</pre>
<h1>Installing Helm</h1>
<p><a href="https://github.com/helm/helm" rel="noopener" target="_blank">Helm</a> is <em>The Kubernetes Package Manager</em>, it helps you to deploy services into Kubernetes.</p>
<pre>
$ wget https://storage.googleapis.com/kubernetes-helm/helm-v2.10.0-linux-amd64.tar.gz -O helm.tar.gz
$ tar zxf helm.tar.gz
$ sudo cp linux-amd64/helm /usr/local/bin/helm
$ sudo chmod +x /usr/local/bin/helm
</pre>
<p>Applying the RBAC policy</p>
<pre>$ kubectl create -f https://raw.githubusercontent.com/nordri/kubernetes-experiments/master/Pipeline/ServiceAccount.yaml</pre>
<p>and then launch helm.</p>
<pre>helm init --service-account tiller</pre>
<p>Checking</p>
<pre>
$ helm version
Client: &version.Version{SemVer:"v2.10.0", GitCommit:"9ad53aac42165a5fadc6c87be0dea6b115f93090", GitTreeState:"clean"}
Server: &version.Version{SemVer:"v2.10.0", GitCommit:"9ad53aac42165a5fadc6c87be0dea6b115f93090", GitTreeState:"clean"}
</pre>
<h1>Deploying Jenkins</h1>
<p>I&#8217;m using a custom values file for this chart. What I&#8217;m adjusting is:</p>
<blockquote><p>
AdminPassword: set to admin1234<br />
ServiceType: set to NodePort (because is Minikube)<br />
In plugins:<br />
    &#8211; kubernetes:1.2<br />
    &#8211; workflow-aggregator:2.5<br />
    &#8211; workflow-job:2.17<br />
    &#8211; credentials-binding:1.15<br />
    &#8211; git:3.7.0
</p></blockquote>
<p>And then the deployment:</p>
<pre>$ helm install --name jenkins -f jenkins-helm-values.yaml stable/jenkins</pre>
<p>After a few minutes we could be able to access Jenkins with:</p>
<pre>$ minikube service jenkins</pre>
<h1>Configuring Jenkins</h1>
<p>First, set the credentials to access Docker Hub where we&#8217;ll push the Docker images. The only field you must keep is <strong>ID</strong> because is needed by the pipeline in a next step. Fill it with your information:</p>
<p><a href="https://www.muspells.net/blog/wp-content/uploads/2018/09/Selección_026.png"><img decoding="async" loading="lazy" src="https://www.muspells.net/blog/wp-content/uploads/2018/09/Selección_026-300x116.png" alt="" width="300" height="116" class="aligncenter size-medium wp-image-1687" srcset="https://www.muspells.net/blog/wp-content/uploads/2018/09/Selección_026-300x116.png 300w, https://www.muspells.net/blog/wp-content/uploads/2018/09/Selección_026-768x298.png 768w, https://www.muspells.net/blog/wp-content/uploads/2018/09/Selección_026.png 782w" sizes="(max-width: 300px) 100vw, 300px" /></a></p>
<p>Back to Jenkins main screen, add a new item type <em>Pipeline</em></p>
<p><a href="https://www.muspells.net/blog/wp-content/uploads/2018/09/Selección_027.png"><img decoding="async" loading="lazy" src="https://www.muspells.net/blog/wp-content/uploads/2018/09/Selección_027-300x191.png" alt="" width="300" height="191" class="aligncenter size-medium wp-image-1688" srcset="https://www.muspells.net/blog/wp-content/uploads/2018/09/Selección_027-300x191.png 300w, https://www.muspells.net/blog/wp-content/uploads/2018/09/Selección_027.png 754w" sizes="(max-width: 300px) 100vw, 300px" /></a></p>
<p>And finally, configure the pipeline in the Pipeline section:</p>
<p><a href="https://www.muspells.net/blog/wp-content/uploads/2018/09/Selección_028.png"><img decoding="async" loading="lazy" src="https://www.muspells.net/blog/wp-content/uploads/2018/09/Selección_028-300x242.png" alt="" width="300" height="242" class="aligncenter size-medium wp-image-1689" srcset="https://www.muspells.net/blog/wp-content/uploads/2018/09/Selección_028-300x242.png 300w, https://www.muspells.net/blog/wp-content/uploads/2018/09/Selección_028-768x621.png 768w, https://www.muspells.net/blog/wp-content/uploads/2018/09/Selección_028.png 849w" sizes="(max-width: 300px) 100vw, 300px" /></a></p>
<p>Save the changes and click on <strong>Build now</strong></p>
<p><a href="https://www.muspells.net/blog/wp-content/uploads/2018/09/Selección_030.png"><img decoding="async" loading="lazy" src="https://www.muspells.net/blog/wp-content/uploads/2018/09/Selección_030-300x125.png" alt="" width="300" height="125" class="aligncenter size-medium wp-image-1691" srcset="https://www.muspells.net/blog/wp-content/uploads/2018/09/Selección_030-300x125.png 300w, https://www.muspells.net/blog/wp-content/uploads/2018/09/Selección_030-768x321.png 768w, https://www.muspells.net/blog/wp-content/uploads/2018/09/Selección_030.png 873w" sizes="(max-width: 300px) 100vw, 300px" /></a></p>
<p>And that&#8217;s it!</p>
<h1>The pipeline</h1>
<p>Let&#8217;s deep into the pipeline</p>
<h2>The head</h2>
<p>The pipeline starts setting the worker id so the pod has different label on each execution.</p>
<p>Follow the pod definition where we can define the containers who will run inside the pod. For this example we&#8217;ll need:</p>
<ol>
<li>maven</li>
<li>docker</li>
<li>mysql, this one with environment variables</li>
<li>java, also with environment variables</li>
</ol>
<p>Then the volumes, we need the docker sock in order to run docker in docker and a folder to save the artefacts downloaded from the Internet (it&#8217;s a Maven project!) between the executions. Saving time and bandwidth.</p>
<h2>Cloning the repo&#8230;</h2>
<p>What we do here is clean the workspace and clone the repository. It a SpringBoot application with MySQL.</p>
<h2>Building&#8230;</h2>
<p>We build the package using maven container.</p>
<h2>Testing&#8230;</h2>
<p>In this stage we launch our app inside Java container and after 30 seconds we check if it online, a simple smoky test. We save the return value in <strong>RES</strong> to decide if it&#8217;s ok or not. If not, finish with <strong>fail</strong>. As we defined all the containers at the beginning there&#8217;s a MySQL running inside the pod.</p>
<h2>Building &#038; Uploading Docker images&#8230;</h2>
<p>If the testing stage went OK, we can push it to Docker Hub. To set the tag we use the commit ID cut to eight characters. To login into Docker Hub we use the <em>withCredentials</em> who takes a credential by id and fill the environment variables.</p>
<h1>References</h1>
<p><a href="https://akomljen.com/set-up-a-jenkins-ci-cd-pipeline-with-kubernetes/" rel="noopener" target="_blank">Set Up a Jenkins CI/CD Pipeline with Kubernetes</a></p>
<h1>Repository</h1>
<p><a href="https://github.com/nordri/kubernetes-experiments/tree/master/Pipeline">GitHub</a></p>
]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1686</post-id>	</item>
	</channel>
</rss>
