Jekyll2023-12-19T22:35:11-06:00https://lgallardo.com/lgallardo.comLuis M. Gallardo D.AWS (re)Certified Solutions Architect - Professional2023-12-18T09:00:55-06:002023-12-18T09:00:55-06:00https://lgallardo.com/2023/12/18/aws-certified-solutions-architect-professional-2023<p><img src="/assets/images/aws-csap-2023.jpg" alt="OctoPrints" style="display:block; margin-left:auto; margin-right:auto" /><br />
This article is to share my experience with the AWS Certified Solutions Architect - Professional (recertification) exam:</p>
<p>If you’re taking the exam for the first time or, as in my case, seeking recertification, I recommend that you review the new content and check what has changed compared to the previous exam. Examples of these changes could be AWS SSO to AWS Identity Center. I also recommend that you familiarize yourself with new services such as AWS Elastic Disaster Recovery, EventBridge, Amazon Managed Services for Apache Flink, among others.</p>
<p>There were 75 questions in 180 minutes. As is typical with AWS professional certifications, the exam is long and features extensive statements and lengthy answers. For those whose native language is not English, this can be confusing, so you will likely have to read several questions more than once (and their options).
If you’re taking the exam for the first time or, as in my case, seeking recertification, I recommend that you review the new content and check what has changed compared to the previous exam. Examples of these changes could be AWS SSO to AWS Identity Center. I also recommend that you familiarize yourself with new services such as AWS Elastic Disaster Recovery, EventBridge, Amazon Managed Services for Apache Flink, among others.
My recommendations for saving time in this exam are:</p>
<ul>
<li>Answer the easy questions quickly; don’t spend too much time pondering whether it’s the correct answer because it most likely is.</li>
<li>Mark the questions where you genuinely have doubts, so when reviewing, you can focus only on those. If time remains, then start reviewing the rest.</li>
<li>Mark multiple-choice questions for review, even if you think they are correct. It’s better to be 100% sure of the options because if you make a mistake in one, the answer can be considered incorrect.</li>
<li>Read the questions carefully because the statement contains the information that will help you eliminate options or choose the correct ones.</li>
<li>Remember that this is an Amazon certification, so always ask yourself which Amazon service is relevant.</li>
<li>Dismiss solutions that can be done at the OS level if an Amazon service provides it, only considering it when there is no other option.</li>
<li>Not everything is solved with Lambda + SQS, even if it seems correct. Review which options or services meet the requirements of the question and don’t be misled by options that initially seem correct.</li>
</ul>
<p>If you are interested in this certification, I recommend some links:</p>
<p><strong>Online courses</strong></p>
<p>For this exam, I stayed loyal to AWS A Cloud Guru, but to be honest, it seems to me that the content is covered superficially, and the course as it stands today looks like a Frankenstein creation. There are at least two instructors with different content formats, as if they had merged the best of Linux Academy’s courses with those of A Cloud Guru. Nonetheless, if you are interested, here it is available:</p>
<ul>
<li><a href="https://www.pluralsight.com/courses/aws-certified-solutions-architect-professional-sap-c02" target="_blank">A Cloud Guru - AWS Certified Solutions Architect Professional</a></li>
</ul>
<p><strong>AWS Documentation</strong></p>
<ul>
<li><a href="https://aws.amazon.com/whitepapers/" target="_blank">Whitepapers</a></li>
<li><a href="https://aws.amazon.com/documentation/" target="_blank">Documentation</a></li>
<li><a href="https://aws.amazon.com/faqs/" target="_blank">FAQs</a></li>
</ul>Luis GallardoThis article is to share my experience with the AWS Certified Solutions Architect - Professional (recertification) exam:OctoPrint with multiple 3D printers2022-09-24T19:00:00-05:002022-09-24T19:00:00-05:00https://lgallardo.com/2022/09/25/octoprint-multiple-printers<p><img src="/assets/images/OctoPrint.jpg" alt="OctoPrints" style="display:block; margin-left:auto; margin-right:auto" /><br />
One of the most useful tools when managing a 3D printer is <a href="https://octoprint.org" target="_blank">OctoPrint</a>, since among several things it allows you to manage your printer from a web interface, as well as adding a lot of functionality (for example, monitoring and management of the printer through Telegram, plugins to generate timelapse videos of the prints, or even detect when there are spaghetti-like problems in our prints using another plugin with AI).</p>
<h2 id="multiple-printers">Multiple printers</h2>
<p>But what if we have more than one printer? Can <strong>OctoPrint</strong> manage more than one printer?</p>
<p>The short answer is: NO! The software itself is not designed for multiple printers, but you can find alternative ways to have more than one instance of <strong>OctoPrint</strong> running on your device or computer.</p>
<p>There are several ways to do this, for example you can <a href="http://thomas-messmer.com/index.php/14-free-knowledge/howtos/79-setting-up- octoprint-for-multiple-printers" target="_blank">modify the OctoPi scripts to add more instances</a>, create scripts that launch multiple instances of the same program, but the option I ended up using was Docker containers.</p>
<h2 id="raspberry-pi--ubuntu">Raspberry Pi + Ubuntu</h2>
<p>In my case I have a <strong>Raspberry Pi 4</strong>, with 8 GB of RAM, more than enough to run multiple instances of <strong>OctoPrint</strong>.</p>
<p>I originally had a specific operating system installed on my Raspberry called <a href="https://github.com/guysoft/OctoPi" target="_blank">OctoPi</a>, a Debian derivative with <strong>OctoPrint</strong> as the main program that is launched when the Raspberry Pi is turned on, but as I wanted to use containers I decided to use Ubuntu, which general purposed distribution where you can surely find everything you need to work with containers.</p>
<h2 id="requirements-and-components">Requirements and components:</h2>
<p>For this setup I used the following:</p>
<ul>
<li>Impresora 3D - Artillery Genius Pro</li>
<li>Impresora 3D - Artillery SideWinder X2</li>
<li>2x WebCam - Logitech C270 (one per printer)</li>
<li>Raspberry Pi 4 - 8G RAM</li>
<li>SD Card 64 GB</li>
<li>Ubuntu 22.04 LTS ARM 64 bits</li>
<li>Docker 20.10.17</li>
<li>OctoPrint lastest (1.8.3)</li>
</ul>
<h2 id="ubuntu-installation">Ubuntu Installation</h2>
<p>Nowadays is easier than ever to install <strong>Ubuntu</strong> on the Raspberry Pi, you just have to download <strong>Raspberry Pi Imager,</strong> which will generate the image on your SD card, select the operating system, which in this case is <strong>Ubuntu 22.04 LTS</strong> and you’re done. <strong>Raspberry Pi Imager</strong> is avialable for Linux, Mac and Windows, so you can generate the image on the operating system that suits you best.</p>
<p><img src="/assets/images/Raspberry-Pi-Imager.jpg" alt="Raspberry Pi Imager" /></p>
<p>From this very software you will have the possibility to configure the password of the WiFi network in case you are using the Raspberry wirelessly, so you don’t need to use a television set and a keyboard (headless), or manipulate the SD card to configure the networking. Since I’m using it headless, that’s what I did and then I connected via <strong>ssh</strong>.</p>
<p><img src="/assets/images/OctoPi-WiFi-Setting.jpg" alt="WiFi Settings" /></p>
<p>For the headless setup the trick is to let the <strong>Ubuntu</strong> initialization scripts run and then connect via ssh. Now if you see that you can’t connect via ssh you can look for an HDMI cable and a keyboard to check what might be going on.</p>
<h2 id="software-installation-on-ubuntu">Software installation on Ubuntu</h2>
<p>Apart from <strong>Docker</strong> we are going to need <strong>docker-compose</strong>, and the utilities that will help us install them.</p>
<h2 id="docker-and-docker-compose">Docker and docker-compose</h2>
<p>To install docker you need to download it using the script. You will need to loging in as the administrator user with the root account:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>pi@octopi:~<span class="nv">$ </span><span class="nb">sudo </span>su
root@octopi:~#
root@octopi:~# apt install curl
root@octopi:~# curl <span class="nt">-sSL</span> https://get.docker.com | sh
root@octopi:~# apt update
root@octopi:~# apt install docker-compose
</code></pre></div></div>
<h2 id="octoprint-with-one-printer">OctoPrint with one printer</h2>
<p>The first thing you need is to create a folder for OctoPrint, and then go into it:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>root@octopi:~# mkdir octoprint
root@octopi:~#
root@octopi:~# <span class="nb">cd </span>octoprint/
root@octopi:~/octoprint#
</code></pre></div></div>
<p>Let’s start with a printer, in this case I’ll start with the <code class="highlighter-rouge">Artillery Genius Pro</code>. For this you can create a folder that identifies this printer:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>root@octopi:~# mkdir geniuspro
root@octopi:~# chmod <span class="nt">-R</span> 777 geniuspro/
</code></pre></div></div>
<p>It’s important to know the actual path because you’ll use it later in the container definition along with the name of this folder. To do this, execute the following command:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>root@octopi:~# <span class="nb">pwd</span>
/root/octoprint
</code></pre></div></div>
<p>With this you can indicate the files of this first instance of OctoPrint will reside in <code class="highlighter-rouge">/root/octoprint/geniuspro</code></p>
<p>Now to configure the printer you need to use <code class="highlighter-rouge">docker-compose</code> so you need to create the <code class="highlighter-rouge">docker-compose.yml</code> file with the following information:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>version: '2.4'
services:
geniuspro:
image: octoprint/octoprint
restart: unless-stopped
ports:
- 5000:5000
- 8080:8080
devices:
- /dev/ttyACM0:/dev/ttyACM0
- /dev/video0:/dev/video0
volumes:
- /root/octoprint/geniuspro:/octoprint
# uncomment the lines below to ensure camera streaming is enabled when
# you add a video device
environment:
- ENABLE_MJPG_STREAMER=true
- CAMERA_DEV=/dev/video0
- MJPG_STREAMER_INPUT="-y -n -r 1280x960 -f 30
</code></pre></div></div>
<p>This file defines various things related to OctoPrint, such as the webcam and the printer itself. For example, <code class="highlighter-rouge">image</code> indicates which Docker image to use for the <code class="highlighter-rouge">geniuspro</code> service.</p>
<p>Notice the ports definitions, where <code class="highlighter-rouge">5000</code> will be used for the web interface and <code class="highlighter-rouge">8080</code> for webcam streaming video.</p>
<p>On the other hand, the printer is defined as a device in <code class="highlighter-rouge">/dev/ttyACM0</code>, and the webcam in <code class="highlighter-rouge">/dev/video0</code></p>
<p>Something to keep in mind and that differs from the <a href="https://docs.google.com/document/d/1aU7LGYAe6r45LqEBQ8opuXCiNKeJl3XrPTrobvEvdOM/edit" target="_blank">example on which I based</a>, is that the streamer is now part of the Docker image and is served on port <code class="highlighter-rouge">8080</code>, so there is no need to have a separate definition of another Docker image pointing to the streamer.</p>
<p><code class="highlighter-rouge">volumes</code> has the reference to the printer directory that you had created as <code class="highlighter-rouge">/root/octoprint/geniuspro</code>, which will be mapped into the container as the <code class="highlighter-rouge">/octoprint</code> folder. That is, when we launch the container all the OctoPrint files for this printer will be in the <code class="highlighter-rouge">/root/octoprint/geniuspro</code> path of the operating system.</p>
<p>Finally, <code class="highlighter-rouge">environment</code> has the streamer parameters, like webcam device from the container. In this case both the OS and the container match the path <code class="highlighter-rouge">/dev/video0</code>. Here you also need to provide you webcam parameters, in my case I indicated that the resolution is 1280x960 at 30 frames per second, which is what corresponds to my Logitech C270. For other models you can consult the <a href="https://community.octoprint.org/t/usb-webcams-known-to-work-with-mjpg-streamer/21149">supported cameras list page</a>.</p>
<p>Once the <code class="highlighter-rouge">docker-compose.yml</code> file has been created with the information shown above, all you have to do is start the service with Docker:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>root@octopi:~/octoprint# docker-compose up -d
Creating octoprint_geniuspro_1 ... done
</code></pre></div></div>
<p>With this we can access the OctoPrint web interface from the Raspberry Pi on the port that we had indicated, in my case the url is http://192.168.68.102:5000:</p>
<p><img src="/assets/images/octoprint-multi-web.jpg" alt="OctoPrint Web 1" /></p>
<h2 id="adding-a-second-printer">Adding a second printer</h2>
<p>To add a second printer, you just have to replicate the configuration you had before, but specifying the new printer and the corresponding video camera. So for my Artillery Sidewinder X2 this would be:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>version: '2.4'
services:
geniuspro:
image: octoprint/octoprint
restart: unless-stopped
ports:
- 5000:5000
- 8080:8080
devices:
- /dev/ttyACM0:/dev/ttyACM0
- /dev/video0:/dev/video0
volumes:
- /root/octoprint/geniuspro:/octoprint
# uncomment the lines below to ensure camera streaming is enabled when
# you add a video device
environment:
- ENABLE_MJPG_STREAMER=true
- CAMERA_DEV=/dev/video0
- MJPG_STREAMER_INPUT="-y -n -r 1280x960 -f 30
sidewinder_x2:
image: octoprint/octoprint
restart: unless-stopped
ports:
- 5000:5000
- 8080:8080
devices:
- /dev/ttyACM1:/dev/ttyACM0
- /dev/video2:/dev/video0
volumes:
- /root/octoprint/geniuspro:/octoprint
# uncomment the lines below to ensure camera streaming is enabled when
# you add a video device
environment:
- ENABLE_MJPG_STREAMER=true
- CAMERA_DEV=/dev/video0
- MJPG_STREAMER_INPUT="-y -n -r 1280x960 -f 30
</code></pre></div></div>
<p>Take into account the phycal printer is identified as <code class="highlighter-rouge">/dev/ttyACM1</code> in the Raspberry , but the container internally it will be see it as <code class="highlighter-rouge">/dev/ttyACM0</code>. The same goes for the video camera, where it is physically identified as <code class="highlighter-rouge">/dev/video2</code> but internally the container will see it as <code class="highlighter-rouge">/dev/video0</code>.</p>
<p>Once the configuration has been created, the container must be run as follows:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>root@octopi:~/octoprint# docker-compose up -d
octoprint_geniuspro_1 is up-to-date
Creating octoprint_sidewinderx2_1 ... done
</code></pre></div></div>
<p>This will now allow access to the second instance of OctoPrint on port 5001:</p>
<p><img src="/assets/images/octoprint-multi-web2.jpg" alt="OctoPrint Web 2" /></p>
<h2 id="how-to-differentiate-printers">How to differentiate printers?</h2>
<p>In the example above I used the devices <code class="highlighter-rouge">/dev/ttyACM0</code> and <code class="highlighter-rouge">/dev/ttyACM1</code> to reference my first printer, the Artillery Genius Pro, and my second printer, the Artillery SideWinder X2, but the operating system not always takes that order, since it will depend on which one you had turned on first. In order to identify the printers regardless of the connection order we can create a symbolic link using <code class="highlighter-rouge">udev</code> with the manufacturer and product information.</p>
<p>For this, you have first list the USB devices:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>root@octopi:~/octoprint# lsusb
Bus 003 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 004: ID 046d:0825 Logitech, Inc. Webcam C270
Bus 001 Device 003: ID 046d:0825 Logitech, Inc. Webcam C270
Bus 001 Device 015: ID 0483:5740 STMicroelectronics Virtual COM Port
Bus 001 Device 016: ID 0483:5740 STMicroelectronics Virtual COM Port
Bus 001 Device 002: ID 2109:3431 VIA Labs, Inc. Hub
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
</code></pre></div></div>
<p>There are two <strong>STMicroelectronics Virtual COM Port</strong> devices here, corresponding to the two printers, but which is which? We are going to ask for the detail of these devices:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code> root@octopi:~/octoprint# lsusb -v -d 0483:5740
Bus 001 Device 015: ID 0483:5740 STMicroelectronics Virtual COM Port
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 2.00
bDeviceClass 2 Communications
bDeviceSubClass 2 Abstract (modem)
bDeviceProtocol 0
bMaxPacketSize0 64
idVendor 0x0483 STMicroelectronics
idProduct 0x5740 Virtual COM Port
bcdDevice 0.00
iManufacturer 1 STMicroelectronics
iProduct 2 ARTILLERY_RUBY CDC in FS Mode
iSerial 3 386F39543538
...
Bus 001 Device 016: ID 0483:5740 STMicroelectronics Virtual COM Port
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 2.00
bDeviceClass 2 Communications
bDeviceSubClass 2 Abstract (modem)
bDeviceProtocol 0
bMaxPacketSize0 64
idVendor 0x0483 STMicroelectronics
idProduct 0x5740 Virtual COM Port
bcdDevice 0.00
iManufacturer 1 STMicroelectronics
iProduct 2 ARTILLERY_RUBY CDC in FS Mode
iSerial 3 3594398F3538
...
</code></pre></div></div>
<p>What differentiates one printer from another is the serial number of the device. Since the Artillery Genius Pro was initially mapped to <code class="highlighter-rouge">/dev/ttyACM0</code>, we can check what its serial number is:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>root@octopi:~/octoprint# udevadm info -a -n /dev/ttyACM0 | grep serial
ATTRS{serial}=="3594398F3538"
ATTRS{serial}=="0000:01:00.0"
</code></pre></div></div>
<p>Now to see the serial code of the Artillery Sidewinder X2 you have to consult the device <code class="highlighter-rouge">/dev/ttyACM1</code>:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
root@octopi:~/octoprint# udevadm info -a -n /dev/ttyACM1 | grep serial
ATTRS{serial}=="386F39543538"
ATTRS{serial}=="0000:01:00.0"
</code></pre></div></div>
<p>For <code class="highlighter-rouge">udev</code> to recognize these rules we must create the following file <code class="highlighter-rouge">/etc/udev/rules.d/40-printers.rules</code> , with this content:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code> # Genius Pro
KERNEL=="ttyACM[0-9]*", SUBSYSTEM=="tty", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="5740", ATTRS{serial}=="3594398F3538", SYMLINK="ttyGeniusPro"
# Sidewinder X2
KERNEL=="ttyACM[0-9]*", SUBSYSTEM=="tty", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="5740", ATTRS{serial}=="386F39543538", SYMLINK="ttySidewinderX2"
</code></pre></div></div>
<p>Then <code class="highlighter-rouge">udev</code> must be restarted to take these changes:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>root@octopi:~/octoprint# udevadm control --reload-rules && udevadm trigger
</code></pre></div></div>
<p>This way the printers will be mapped as follows:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>root@octopi:~/octoprint# ls -l /dev/tty{GeniusPro,Sidewinder}*
lrwxrwxrwx 1 root root 7 Aug 22 21:10 /dev/ttyGeniusPro -> ttyACM0
lrwxrwxrwx 1 root root 7 Aug 22 21:10 /dev/ttySidewinderX2 -> ttyACM1
</code></pre></div></div>
<p>So the Docker configuration can be modified to reflect these changes:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>version: '2.4'
services:
geniuspro:
image: octoprint/octoprint
restart: unless-stopped
ports:
- 5000:5000
- 8080:8080
devices:
- /dev/ttyGeniusPro:/dev/ttyACM0
- /dev/video0:/dev/video0
volumes:
- /root/octoprint/geniuspro:/octoprint
# uncomment the lines below to ensure camera streaming is enabled when
# you add a video device
environment:
- ENABLE_MJPG_STREAMER=true
- CAMERA_DEV=/dev/video0
- MJPG_STREAMER_INPUT="-y -n -r 1280x960 -f 30
sidewinderx2:
image: octoprint/octoprint
restart: unless-stopped
ports:
- 5001:5000
- 8081:8080
devices:
- /dev/ttySidewinderX2:/dev/ttyACM0
- /dev/video2:/dev/video0
volumes:
- /root/octoprint/sidewinderx2:/octoprint
# uncomment the lines below to ensure camera streaming is enabled when
# you add a video device
environment:
- ENABLE_MJPG_STREAMER=true
- CAMERA_DEV=/dev/video0
- MJPG_STREAMER_INPUT="-y -n -r 1280x960 -f 30
</code></pre></div></div>
<h2 id="webcams">Webcams</h2>
<p>Unlike printers which have different serial numbers, I have two <strong>Logitech C270</strong> webcams that are exactly the same model. How can we differente them? How can we make the OS to take the right camera?</p>
<p>Again we do the analysis with <code class="highlighter-rouge">lsusb</code>:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>root@octopi:~/octoprint# lsusb
Bus 003 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 004: ID 046d:0825 Logitech, Inc. Webcam C270
Bus 001 Device 003: ID 046d:0825 Logitech, Inc. Webcam C270
Bus 001 Device 015: ID 0483:5740 STMicroelectronics Virtual COM Port
Bus 001 Device 016: ID 0483:5740 STMicroelectronics Virtual COM Port
Bus 001 Device 002: ID 2109:3431 VIA Labs, Inc. Hub
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
</code></pre></div></div>
<p>Both cameras are on the same bus but identified as different USB devices, which we can take advantage of. In this case we will not use the product id to differentiate them but the USB device id. We’ll be referencing the <code class="highlighter-rouge">video4linux</code> subsystem instead of <code class="highlighter-rouge">tty</code>, so we’ll be using <code class="highlighter-rouge">KERNELS</code> instead of <code class="highlighter-rouge">KERNEL</code> to differentiate cameras. For example, to find out which USB device the camera in <code class="highlighter-rouge">/dev/video0</code> is on, we can run the following:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>root@octopi:~/octoprint# udevadm info -a -p $(udevadm info -q path -n /dev/video0) | grep KERNELS
KERNELS=="1-1.4:1.0"
KERNELS=="1-1.4"
KERNELS=="1-1"
KERNELS=="usb1"
KERNELS=="0000:01:00.0"
KERNELS=="0000:00:00.0"
KERNELS=="pci0000:00"
KERNELS=="fd500000.pcie"
KERNELS=="scb"
KERNELS=="platform"
</code></pre></div></div>
<p>For the other camera we do the same:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>root@octopi:~/octoprint# udevadm info -a -p $(udevadm info -q path -n /dev/video2) | grep KERNELS
KERNELS=="1-1.3:1.0"
KERNELS=="1-1.3"
KERNELS=="1-1"
KERNELS=="usb1"
KERNELS=="0000:01:00.0"
KERNELS=="0000:00:00.0"
KERNELS=="pci0000:00"
KERNELS=="fd500000.pcie"
KERNELS=="scb"
KERNELS=="platform"
</code></pre></div></div>
<p>Now with this information we can modify the <code class="highlighter-rouge">udev</code> rules as follows:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Genius Pro
KERNEL=="ttyACM[0-9]*", SUBSYSTEM=="tty", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="5740", ATTRS{serial}=="3594398F3538", SYMLINK="ttyGeniusPro"
SUBSYSTEM=="video4linux", KERNELS=="1-1.3", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="0825", SYMLINK="videoGeniusPro"
# Sidewinder X2
KERNEL=="ttyACM[0-9]*", SUBSYSTEM=="tty", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="5740", ATTRS{serial}=="386F39543538", SYMLINK="ttySidewinderX2"
SUBSYSTEM=="video4linux", KERNELS=="1-1.4", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="0825", SYMLINK="videoSidewinderX2"
</code></pre></div></div>
<p>Remember to reset the <code class="highlighter-rouge">udev</code> rules with:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>root@octopi:~/octoprint# udevadm control --reload-rules && udevadm trigger
</code></pre></div></div>
<p>So now we have the cameras mapped to <code class="highlighter-rouge">/dev/videoGeniusPro</code> and <code class="highlighter-rouge">/dev/videoSidewinderX2</code> respectively. Now we can modify the <strong>docker-compose.yml</strong> file to take this new configuration:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>version: '2.4'
services:
geniuspro:
image: octoprint/octoprint
restart: unless-stopped
ports:
- 5000:5000
- 8080:8080
devices:
- /dev/ttyGeniusPro:/dev/ttyACM0
- /dev/videoGeniusPro:/dev/video0
volumes:
- /root/octoprint/geniuspro:/octoprint
# uncomment the lines below to ensure camera streaming is enabled when
# you add a video device
environment:
- ENABLE_MJPG_STREAMER=true
- CAMERA_DEV=/dev/video0
- MJPG_STREAMER_INPUT="-y -n -r 1280x960 -f 30
sidewinderx2:
image: octoprint/octoprint
restart: unless-stopped
ports:
- 5001:5000
- 8081:8080
devices:
- /dev/ttySidewinderX2:/dev/ttyACM0
- /dev/videoSidewinderX2:/dev/video0
volumes:
- /root/octoprint/sidewinderx2:/octoprint
# uncomment the lines below to ensure camera streaming is enabled when
# you add a video device
environment:
- ENABLE_MJPG_STREAMER=true
- CAMERA_DEV=/dev/video0
- MJPG_STREAMER_INPUT="-y -n -r 1280x960 -f 30
</code></pre></div></div>
<h2 id="performance-with-two-instances-of-octoprint">Performance with two instances of OctoPrint</h2>
<p>Probably you are wondering about the consumption of these containers in the operating system and if the Raspberry can handle it. Here is an image of <code class="highlighter-rouge">htop</code> with the two containers above printing to each of the printers at the same time.</p>
<p><img src="/assets/images/octoprint-htop.jpg" alt="htop" /></p>
<p>As you can see the Raspberry has a lot of resources available, since of the 8GB of RAM it is only consuming 0.5 GB including the operating system. From this we can draw two conclusions: the first one is that more printers can be added without problems, the only limit is the number of USB ports offered by the Raspberry (4 in my model), but you could add a USB hub to add more ports; and the second conclusion is that for two printers you could use a Raspberry with less RAM, for example 2 GB or 4 GB, and thus you would save a little.</p>
<h2 id="what-does-the-raspberry-pi-and-printers-look-like">What does the Raspberry Pi and printers look like?</h2>
<p>To finish this article I leave you a photo of my printers connected to the RaspBerry Pi:</p>
<p><img src="/assets/images/3dprinters.jpg" alt="3D printers" /></p>
<p>On the smaller printer you can see a small gray box that is the Raspberry Pi, next to the two web cameras.</p>
<h1 id="references">References</h1>
<ul>
<li><a href="https://octoprint.org" target="_blank">OctoPrint</a></li>
<li><a href="https://github.com/guysoft/OctoPi" target="_blank">OctoPi</a></li>
<li><a href="http://thomas-messmer.com/index.php/14-free-knowledge/howtos/79-setting-up-octoprint-for-multiple-printers" target="_blank">Setting up OctoPrint on a Raspberry Pi for multiple printers</a></li>
<li><a href="https://youtu.be/LcA9o6OGfEg" target="_blank">Installing OctoPrint using Docker in Linux (video tutorial)</a></li>
<li><a href="https://docs.google.com/document/d/1aU7LGYAe6r45LqEBQ8opuXCiNKeJl3XrPTrobvEvdOM/edit" target="_blank">Installing OctoPrint using Docker in Linux (instructions)</a></li>
<li><a href="https://community.octoprint.org/t/usb-webcams-known-to-work-with-mjpg-streamer/21149" target="_blank">USB webcams known to work with mjpg-streamer</a>.</li>
<li><a href="https://askubuntu.com/questions/49910/how-to-distinguish-between-identical-usb-to-serial-adapters" target="_blank">How to distinguish between identical USB-to-serial adapters?</a></li>
<li><a href="https://unix.stackexchange.com/questions/424887/udev-rule-to-discern-2-identical-webcams-on-linux" target="_blank">Udev Rule to discern 2 identical webcams on Linux</a></li>
</ul>Luis GallardoOne of the most useful tools when managing a 3D printer is OctoPrint, since among several things it allows you to manage your printer from a web interface, as well as adding a lot of functionality (for example, monitoring and management of the printer through Telegram, plugins to generate timelapse videos of the prints, or even detect when there are spaghetti-like problems in our prints using another plugin with AI).PaperLike Pencil Grips2022-04-17T00:00:00-05:002022-04-17T00:00:00-05:00https://lgallardo.com/2022/04/17/paperlike-pencil-grips<p><img src="/assets/images/PaperLike-Pencil-Grip.jpg" alt="PaperLike Pencil Grips" style="display:block; margin-left:auto; margin-right:auto" /><br />
I’ve been using my iPad for a while to take notes with the Apple Pencil and I decided to write this article to tell you about a product that has pleasantly surprised me and which I think is an excellent improvement to consider: the <strong>Paper Like Pencil Grips</strong>.</p>
<p>It may have happened to you that when using the Apple Pencil for a long time, your hand gets tired? This is common even with traditional pencils, and for this there was already a solution, the classic grips adapted to the pencil to improve the posture of the fingers when writing. This is what the PaperLike team ended up designing, but for the Apple Pencil.</p>
<p>You’ll say that they are simple grips and probably you think you can use traditional grips to adapt them to the Apple Pencil…Yes, for little money you can put a generic grip on it but there’re a couple of things that you should consider, that the PaperLike team has already solved and that you won’t have with a generic product:</p>
<h2 id="apple-pencils-magnetic-charge">Apple Pencil’s magnetic charge</h2>
<p><img src="/assets/images/Grip-on-iPad.jpg" alt="Blink config" style="display:block; margin-left:auto; margin-right:auto" /></p>
<p>They achieve this thanks to the fact their grips are specially designed for the Apple Pencil, since they have the shape of the pencil, and the side used for magnetic charging is slightly thinner.</p>
<h2 id="the-posture-of-the-fingers">The posture of the fingers</h2>
<p>The PaperLike guys took into account two edge cases: precision and prolonged periods of use. Yes, two different pencil grips come in the envelop: The first is aimed at having maximum precision when grabbing the pencil, for example when you need fine details when drawing. The second one is designed to help those who take notes for a long time, ideal for university students.</p>
<p>In my case, I really enjoy the grip for long session using (although I left behind my university yeas a long time ago), but I am sure this will be very useful for students, and for artists (professional or not) it will be help them to have more precise lines when making their creations.</p>
<p>It is definitely an improvement that undoubtedly changes the experience of using the iPad and the Apple Pencil.</p>
<h2 id="double-tap-funtion">Double tap funtion</h2>
<p>The Apple Pencil has a second function that is activated by double-tapping the flat part of the pencil. With a generic grip there’s no way to double tap. The PaperLike Pencil Grips achieves this with the thinnest part of the grip. But I must comment that to use it you have to turn the pencil to be able to double tap. I use this a lot in <strong>GoodNotes 5</strong>, and it’s not that natural. In fact, the founder of PaperLike in the How-To video comments that one option is to use the grip with that part facing up, but I think it loses its grace becuase the grip’s shape was designed for the index fingers and the thumb. It seemed to me that the best option is to get used to turning the pencil before doing the double tap, and turning it back to continue writing.</p>
<h1 id="the-packaging">The packaging</h1>
<p>Finally, I would like to highlight something pleasant, which is the packaging in which it came. As I bought the grips at an early stage, they came in a paper envelope, which in fact they make clear is not the final packaging for the product.</p>
<p><img src="/assets/images/PaperLike-Pencil-Grips-Envelop.jpg" alt="PaperLike Pencil Grips Packing" style="display:block; margin-left:auto; margin-right:auto" /></p>
<p>In particular, it doesn’t bother me at all and in fact I would even say that it should be the final version, a simple and environmentally friendly presentation. The only thing that would suggest to improve is that the material of the envelope, it should be a little harder so that it can withstand the onslaught of the trip, or in any case they should send them in “fragile” correspondence, since the shipment was not at all economical (€ 39.99). In my case, mine arrived in that envelope a little wrinkled, and the contents also wrinkled.</p>
<p>Other details that I liked were the thank you note they place on the packaging, handwritten by the founder of PaperLike (and then printed industrially), as well as a very nice sticker that they add from the community of artists who use their products.</p>
<p><img src="/assets/images/PaperLike-Pencil-Grips-thanks.jpg" alt="PaperLike Pencil Grips thanking note" style="display:block; margin-left:auto; margin-right:auto" /></p>
<p><img src="/assets/images/PaperLike-Pencil-Grips-Sticker.jpg" alt="PaperLike Pencil Grips sticker gift" style="display:block; margin-left:auto; margin-right:auto" /></p>
<h1 id="where-to-buy-the-paperlike-grips">Where to buy the PaperLike Grips?</h1>
<p>As I mentioned, they are at an early stage, so at the moment the only place you will be able to buy them in PaperLike’s store, got to <a href="https://paperlike.com/collections/ipad-accessories" target="_blank">iPad accessories</a> , here the <a href="https://paperlike.com/collections/ipad-accessories/products/pencil-grip-set" target="_blank">PaperLike Pencil Grips are available.</a></p>
<h1 id="conclusion">Conclusion</h1>
<p>If you need a grip for your Apple Pencil, keep in mind this option offered by the PaperLike guys, which will undoubtedly improve your user experience on your iPad significantly.</p>
<h2 id="disclaimer">Disclaimer</h2>
<p>I wrote this post to share my experience with the PaperLike pencil grips, and I did not receive any sponsorship or have any profit or participation in their sales.</p>
<h1 id="references">References</h1>
<ul>
<li><a href="https://paperlike.com" target="_blank">PaperLike page</a></li>
<li><a href="https://paperlike.com/collections/ipad-accessories" target="_blank">iPad Accessories</a></li>
<li><a href="https://paperlike.com/collections/ipad-accessories/products/pencil-grip-set" target="_blank">PaperLike Pencil Grips</a></li>
</ul>Luis GallardoI’ve been using my iPad for a while to take notes with the Apple Pencil and I decided to write this article to tell you about a product that has pleasantly surprised me and which I think is an excellent improvement to consider: the Paper Like Pencil Grips.iPad Pro as portable workstation2022-01-24T18:00:00-06:002022-01-24T18:00:00-06:00https://lgallardo.com/2022/01/25/ipad-pro-as-a-portable-workstation<p><img src="/assets/images/ipad-pro-2021.jpg" alt="iPad Pro" style="display:block; margin-left:auto; margin-right:auto" /><br />
It’s been a while since I posted on the blog, first because I couldn’t find something interesting to share and second because there wasn’t much spare time (It’s not that now there’s a lot of time to spare but well, one make some time to write a few lines).</p>
<p>The truth is I recently got an iPad Pro 11” and among the things I tried was the possibility to use it as a light work equipment, that is, a computer that I can have on hand on my bedside table without it being a complete computer.</p>
<p>While the iPad has many advantages and things that I really liked, it seems the term “Pro” is not enough to have a complete terminal as you can find in an operating system or to have a functional <a href="https://youtu.be/LrLDKYFyLMM" target="_blank">virtual machine</a>, so I decided to investigate if there is an option to use it as a client that connects somewhere else where I can have access to a complete operating system.</p>
<p>In fact, I read an <a href="https://arslan.io/2019/01/07/using-the-ipad-pro-as-my-development-machine/" target="_blank">article</a> that suggested using a Digital Ocean Droplet to have a virtual machine in the cloud and from there be able to work. This option is not bad, but having a workstation at home I didn’t see the need to go to the cloud.</p>
<p>Following some of these suggestions I ended up installing <strong>Blink Shell</strong> that comes with <code class="highlighter-rouge">mosh</code> support, and using <code class="highlighter-rouge">tmux</code> on my remote Linux laptop I was able to achieve this. Below I explain the details of this configuration.</p>
<h1 id="blink-shell-ssh--mosh">Blink Shell (ssh / mosh)</h1>
<p>The first thing I had to look for was a decent <code class="highlighter-rouge">ssh</code> client for iPad. <strong><a href="https://blink.sh" target="_blank">Blink Shell</a></strong> appeared as recurring recommendation on Internet articles. At first, I didn’t like the fact you have to buy it without a trial but since there were several recommendations I gave it a try (USD 19.99 at the date of publication of this post).</p>
<p>I have to admit <strong>Blink Shell</strong> is very, very good, it’s designed for mobile devices and has support for <code class="highlighter-rouge">mosh</code>.</p>
<h2 id="mosh">Mosh</h2>
<p>Maybe you are wondering as I did, What is <code class="highlighter-rouge">mosh</code>? The definition from the <code class="highlighter-rouge">mosh</code> page says:</p>
<blockquote>
<p>Remote terminal application that allows roaming, supports intermittent connectivity, and provides intelligent local echo and line editing of user keystrokes.</p>
</blockquote>
<p>Do you still not understand what <code class="highlighter-rouge">mosh</code> is for as it happened to me? It’s like <code class="highlighter-rouge">screen</code> but without having to learn commands to create and manage sessions, it also uses <code class="highlighter-rouge">ssh</code> under the hood. In other words, you will have the possibility to continue working on your session where you left it off, or if for example your connection was cut and you manage to connect again to another network.</p>
<p>As under the hood it uses <code class="highlighter-rouge">ssh</code>, in order to use <code class="highlighter-rouge">mosh</code> the syntax is practically the same. Therefore if you used to connect to a server using <code class="highlighter-rouge">ssh</code> like this:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssh lgallard@192.168.1.65
</code></pre></div></div>
<p>Now with <code class="highlighter-rouge">mosh</code> you can connect to the server as follows:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mosh lgallard@192.168.1.65
</code></pre></div></div>
<p>The change seems simple and with this we now are able to close our iPad or the computer where we are using the <code class="highlighter-rouge">mosh</code> client and be able to magically recover the work session when we reconnect.</p>
<p>You can configure <strong>Blink Shell</strong> options by accessing a configuration wizard to have different hosts and ease the connection with a name instead of an IP address. To access this wizard simply type <code class="highlighter-rouge">config</code> from the terminal:</p>
<p><img src="/assets/images/Blink_config.png" alt="Blink config" style="display:block; margin-left:auto; margin-right:auto" /></p>
<p>In my case now I can connect to my workstation as follows:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mosh dauntless
</code></pre></div></div>
<h2 id="mosh-the-bad">Mosh, the bad</h2>
<p>As a con <code class="highlighter-rouge">mosh</code> can’t scroll the terminal, that is, if you need to check the output of commands that you have previously executed and are no longer on the screen, you won’t be able to see them. For me, this was a big problem because when using <code class="highlighter-rouge">terraform</code> I lost the plans with the changes to be applied.</p>
<p>This is the way <code class="highlighter-rouge">mosh</code> works, to have optimal performance they render the text. There’s an <a href="https://github.com/mobile-shell/mosh/issues/122" target="_blank">open issue</a> since several years where the developers commented they left it opened as a reference but they have no intention of implementing it. So, is there no solution? Yes, <code class="highlighter-rouge">tmux</code>.</p>
<h1 id="what-is-tmux">What is tmux?</h1>
<p><code class="highlighter-rouge">tmux</code> is a tool that allows you to have several terminals open (or windows) to be accessed and controlled from a single terminal as we would do with <code class="highlighter-rouge">screen</code>.</p>
<p>You have to install <code class="highlighter-rouge">tmux</code> on the computer where we want to log in and once installed it’s enough to run this from the <code class="highlighter-rouge">mosh</code> client (the iPad Pro in my case):</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mosh danuntless -- tmux new -s terminal-1
</code></pre></div></div>
<p>This way we can create a new session whose name is <strong>terminal-1</strong>. Then to access this session later you have to run the following:</p>
<p><code class="highlighter-rouge">mosh danuntless -- tmux a -t terminal-1</code></p>
<h2 id="enabling--scrolling-on-tmux">Enabling scrolling on tmux</h2>
<p>On the remote workstation you must configure <code class="highlighter-rouge">mosh</code> to have scrolling enabled using <code class="highlighter-rouge">tmux</code>, to achieve this edit the <code class="highlighter-rouge">~/.tmux.conf</code> file with this content:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>new-session
set -g history-limit 30000
set -g mouse on
</code></pre></div></div>
<h2 id="blink--ssh---mosh--tmux--eh">Blink + ssh + mosh + tmux … eh?</h2>
<p>“Wait a moment … <strong>Blink + ssh + mosh + tmux</strong>, Are all these too complicated? Isn’t it better to use <code class="highlighter-rouge">ssh</code> with <code class="highlighter-rouge">screen</code>? “. Yes, it’s an alternative, but with <code class="highlighter-rouge">ssh</code> you would not be able to reconnect automatically and you will have to log in again if you close the iPad or if your IP address changes for some reason (for example, if you change your connection from WiFI to cell phone) or if the <code class="highlighter-rouge">ssh</code> session expires.</p>
<p>I have to admit there’s a learning curve to cover with <code class="highlighter-rouge">tmux</code> but once passed you will love it and wonder why you didn’t use <code class="highlighter-rouge">mosh</code> and <code class="highlighter-rouge">tmux</code> before.</p>
<h2 id="more-about-tmux">More about tmux</h2>
<p>If you want to learn how to use <code class="highlighter-rouge">tmux</code> I leave you a <a href="https://tmuxcheatsheet.com" target="_blank">cheat sheet</a> with the commands you can use. In my case, I found the panels division and the use of zooming between them very useful, but I must admit that copying text between panels is somewhat complicated on the iPad and sometimes I prefer to use <code class="highlighter-rouge">vim</code> for this, but I will surely find a workaround.</p>
<h1 id="final-words">Final words</h1>
<p>Here I comment my experiences with the iPad Pro, but all these can be replicated on an iPad Air and even use <code class="highlighter-rouge">mosh</code> and <code class="highlighter-rouge">tmux</code> from other workstations with Linux or Windows.</p>
<h1 id="references">References</h1>
<ul>
<li><a href="https://youtu.be/LrLDKYFyLMM" target="_blank">Run ANY OS on iPad or iPhone! - YouTube</a></li>
<li><a href="https://arslan.io/2019/01/07/using-the-ipad-pro-as-my-development-machine/" target="_blank">Using the iPad Pro as my development machine</a></li>
<li><a href="https://blink.sh" target="_blank">Blink Shell</a></li>
<li><a href="https://blink.sh" target="_blank">Mosh</a></li>
<li><a href="https://tmuxcheatsheet.com">Tmux cheat sheet</a></li>
<li><a href="https://github.com/mobile-shell/mosh/issues/122" target="_blank">mosh prevents the use of scrollback</a></li>
</ul>Luis GallardoIt’s been a while since I posted on the blog, first because I couldn’t find something interesting to share and second because there wasn’t much spare time (It’s not that now there’s a lot of time to spare but well, one make some time to write a few lines).Helm 3 local repo2021-06-14T19:00:00-05:002021-06-14T19:00:00-05:00https://lgallardo.com/2021/06/15/helm3-local-repo<p><img src="/assets/images/helm.jpg" alt="Helm 3 local repo" style="display:block; margin-left:auto; margin-right:auto" />
In Helm 3 the support of <strong>helm serve</strong> command was removed due to some design issues, therefore if you need a similar tool you have to install <strong>helm servecm</strong> plugin, which uses <strong>ChartMuseum</strong> for publishing the charts to your local storage (other storages are also supported, like S3 buckets).</p>
<p>In this post you will learn how to install and publish a local repo in Helm 3.</p>
<ol>
<li>Install <strong>ChartMuseum</strong><br />
First off, you need to install <strong>ChartMuseum</strong>. At the project page you will find different ways of installing it, but I install as a Go app as follows:<br /><br />
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">GO111MODULE</span><span class="o">=</span><span class="s2">"on"</span> go get github.com/helm/chartmuseum@v0.13.1
</code></pre></div> </div>
</li>
<li>
<p>Install <strong>helm servecm plugin</strong><br /></p>
<p><br />Then you need to install <strong>servecm</strong> as a helm plugin:<br /><br /></p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>helm plugin install https://github.com/jdolitsky/helm-servecm
</code></pre></div> </div>
</li>
<li>
<p>Install <strong>helm push plugin</strong><br />
In order to host your charts, you will be using <strong>ChartMuseum</strong> and <strong>helm servecm</strong> pluing, but you will still need to publish them into <strong>ChartMuseum</strong>. You can do it manually or use another plugin called <strong>helm push</strong> which does it for you:<br /><br /></p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>helm plugin install https://github.com/chartmuseum/helm-push.git
</code></pre></div> </div>
</li>
<li>
<p>Add the local repo in helm:<br /><br /></p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>helm repo add local http://127.0.0.1:8879/charts
</code></pre></div> </div>
</li>
<li>
<p>Run <strong>helm servecm plugin</strong>:</p>
<p><br />Next step is to run <strong>helm servecm</strong> plugin:<br /><br /></p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>helm servecm <span class="nt">--port</span><span class="o">=</span>8879 <span class="nt">--storage</span> <span class="nb">local</span> <span class="nt">--storage-local-rootdir</span> ./local <span class="nt">--context-path</span><span class="o">=</span>/charts
</code></pre></div> </div>
<p>Now you can publish your charts at http://127.0.0.1:8879/charts</p>
</li>
<li>
<p>Publish your chart to your local repo:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>helm push your-chart <span class="nb">local</span>
</code></pre></div> </div>
</li>
</ol>
<p>At this point you will be able to use you local charts in your cluster by executing:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>helm install your-chart
</code></pre></div></div>
<h2 id="references">References</h2>
<ul>
<li><a href="https://helm.sh/docs/faq/#removal-of-helm-serve" target="_blank">Removal of helm serve</a></li>
<li><a href="https://github.com/jdolitsky/helm-servecm" target="_blank">helm servecm plugin</a></li>
<li><a href="https://github.com/helm/chartmuseum" target="_blank">ChartMuseum</a></li>
<li><a href="https://github.com/chartmuseum/helm-push" target="_blank">helm push plugin</a></li>
</ul>Luis GallardoIn Helm 3 the support of helm serve command was removed due to some design issues, therefore if you need a similar tool you have to install helm servecm plugin, which uses ChartMuseum for publishing the charts to your local storage (other storages are also supported, like S3 buckets).Terraform module for AWS ECR2021-04-15T00:00:00-05:002021-04-15T00:00:00-05:00https://lgallardo.com/2021/04/15/terraform-module-for-aws-ecr<center><img src="/images/terraform-aws-ecr.jpg" alt="Terraform" /></center>
<p><br />
I share here another Terraform module I published as open source code, which allows you to create registries in AWS ECR.</p>
<p>You can check my module <strong>terraform-aws-ecr</strong> at the <a href="https://registry.terraform.io/modules/lgallard/ecr/aws" target="_blank">Terraform Registry</a> or clone it from <a href="https://github.com/lgallard/terraform-aws-ecr.git" target="_blank">Github</a>.</p>
<p>If you want to take a sneak of the module, I also left the README in this post:</p>
<p><img src="https://lgallardo.com/images/terraform.jpg" alt="Terraform" target="_blank" /></p>
<h1 id="terraform-aws-ecr">terraform-aws-ecr</h1>
<p>Terraform module to create <a href="https://aws.amazon.com/ecr/" target="_blank">AWS ECR</a> (Elastic Container Registry) which is a fully-managed Docker container registry.</p>
<h2 id="usage">Usage</h2>
<p>You can use this module to create an ECR registry using few parameters (simple example) or define in detail every aspect of the registry (complete example).</p>
<p>Check the <a href="https://github.com/lgallard/terraform-aws-ecr/tree/master/examples" target="_blank">examples</a> for the <strong>simple</strong> and the <strong>complete</strong> snippets.</p>
<h3 id="simple-example">Simple example</h3>
<p>This example creates an ECR registry using few parameters</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>module "ecr" {
source = "lgallard/ecr/aws"
name = "ecr-repo-dev"
# Tags
tags = {
Owner = "DevOps team"
Environment = "dev"
Terraform = true
}
}
</code></pre></div></div>
<h3 id="complete-example">Complete example</h3>
<p>In this example the register is defined in detailed.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>module "ecr" {
source = "lgallard/ecr/aws"
name = "ecr-repo-dev"
scan_on_push = true
timeouts_delete = "60m"
image_tag_mutability = "MUTABLE"
# Note that currently only one policy may be applied to a repository.
policy = <<EOF
{
"Version": "2008-10-17",
"Statement": [
{
"Sid": "repo policy",
"Effect": "Allow",
"Principal": "*",
"Action": [
"ecr:GetDownloadUrlForLayer",
"ecr:BatchGetImage",
"ecr:BatchCheckLayerAvailability",
"ecr:PutImage",
"ecr:InitiateLayerUpload",
"ecr:UploadLayerPart",
"ecr:CompleteLayerUpload",
"ecr:DescribeRepositories",
"ecr:GetRepositoryPolicy",
"ecr:ListImages",
"ecr:DeleteRepository",
"ecr:BatchDeleteImage",
"ecr:SetRepositoryPolicy",
"ecr:DeleteRepositoryPolicy"
]
}
]
}
EOF
# Only one lifecycle policy can be used per repository.
# To apply multiple rules, combined them in one policy JSON.
lifecycle_policy = <<EOF
{
"rules": [
{
"rulePriority": 1,
"description": "Expire untagged images older than 14 days",
"selection": {
"tagStatus": "untagged",
"countType": "sinceImagePushed",
"countUnit": "days",
"countNumber": 14
},
"action": {
"type": "expire"
}
},
{
"rulePriority": 2,
"description": "Keep last 30 dev images",
"selection": {
"tagStatus": "tagged",
"tagPrefixList": ["dev"],
"countType": "imageCountMoreThan",
"countNumber": 30
},
"action": {
"type": "expire"
}
}
]
}
EOF
# Tags
tags = {
Owner = "DevOps team"
Environment = "dev"
Terraform = true
}
}
</code></pre></div></div>
<h2 id="providers">Providers</h2>
<table>
<thead>
<tr>
<th>Name</th>
<th>Version</th>
</tr>
</thead>
<tbody>
<tr>
<td>aws</td>
<td>n/a</td>
</tr>
</tbody>
</table>
<h2 id="inputs">Inputs</h2>
<table>
<thead>
<tr>
<th>Name</th>
<th>Description</th>
<th>Type</th>
<th>Default</th>
<th style="text-align: center">Required</th>
</tr>
</thead>
<tbody>
<tr>
<td>encryption_type</td>
<td>The encryption type to use for the repository. Valid values are <code class="highlighter-rouge">AES256</code> or <code class="highlighter-rouge">KMS</code></td>
<td><code class="highlighter-rouge">string</code></td>
<td><code class="highlighter-rouge">"AES256"</code></td>
<td style="text-align: center">no</td>
</tr>
<tr>
<td>image_scanning_configuration</td>
<td>Configuration block that defines image scanning configuration for the repository. By default, image scanning must be manually triggered. See the ECR User Guide for more information about image scanning.</td>
<td><code class="highlighter-rouge">map</code></td>
<td><code class="highlighter-rouge">{}</code></td>
<td style="text-align: center">no</td>
</tr>
<tr>
<td>image_tag_mutability</td>
<td>The tag mutability setting for the repository. Must be one of: <code class="highlighter-rouge">MUTABLE</code> or <code class="highlighter-rouge">IMMUTABLE</code>.</td>
<td><code class="highlighter-rouge">string</code></td>
<td><code class="highlighter-rouge">"MUTABLE"</code></td>
<td style="text-align: center">no</td>
</tr>
<tr>
<td>kms_key</td>
<td>The ARN of the KMS key to use when encryption_type is <code class="highlighter-rouge">KMS</code>. If not specified when encryption_type is <code class="highlighter-rouge">KMS</code>, uses a new KMS key. Otherwise, uses the default AWS managed key for ECR.</td>
<td><code class="highlighter-rouge">string</code></td>
<td>n/a</td>
<td style="text-align: center">no</td>
</tr>
<tr>
<td>lifecycle_policy</td>
<td>Manages the ECR repository lifecycle policy</td>
<td><code class="highlighter-rouge">string</code></td>
<td>n/a</td>
<td style="text-align: center">yes</td>
</tr>
<tr>
<td>name</td>
<td>Name of the repository.</td>
<td><code class="highlighter-rouge">string</code></td>
<td>n/a</td>
<td style="text-align: center">yes</td>
</tr>
<tr>
<td>policy</td>
<td>Manages the ECR repository policy</td>
<td><code class="highlighter-rouge">string</code></td>
<td>n/a</td>
<td style="text-align: center">yes</td>
</tr>
<tr>
<td>scan_on_push</td>
<td>Indicates whether images are scanned after being pushed to the repository (true) or not scanned (false).</td>
<td><code class="highlighter-rouge">bool</code></td>
<td><code class="highlighter-rouge">true</code></td>
<td style="text-align: center">no</td>
</tr>
<tr>
<td>tags</td>
<td>A mapping of tags to assign to the resource.</td>
<td><code class="highlighter-rouge">map(string)</code></td>
<td><code class="highlighter-rouge">{}</code></td>
<td style="text-align: center">no</td>
</tr>
<tr>
<td>timeouts</td>
<td>Timeouts map.</td>
<td><code class="highlighter-rouge">map</code></td>
<td><code class="highlighter-rouge">{}</code></td>
<td style="text-align: center">no</td>
</tr>
<tr>
<td>timeouts_delete</td>
<td>How long to wait for a repository to be deleted.</td>
<td><code class="highlighter-rouge">string</code></td>
<td>n/a</td>
<td style="text-align: center">no</td>
</tr>
</tbody>
</table>
<h2 id="outputs">Outputs</h2>
<table>
<thead>
<tr>
<th>Name</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>arn</td>
<td>Full ARN of the repository</td>
</tr>
<tr>
<td>name</td>
<td>The name of the repository.</td>
</tr>
<tr>
<td>registry_id</td>
<td>The registry ID where the repository was created.</td>
</tr>
<tr>
<td>repository_url</td>
<td>The URL of the repository (in the form <code class="highlighter-rouge">aws_account_id.dkr.ecr.region.amazonaws.com/repositoryName</code>)</td>
</tr>
</tbody>
</table>
<h2 id="references">References</h2>
<ul>
<li><a href="https://github.com/lgallard/terraform-aws-ecr.git" target="_blank">terraform-aws-ecr module at Github</a></li>
<li><a href="https://registry.terraform.io/modules/lgallard/ecr/aws" target="_blank">terraform-aws-ecr module at Terraform Registry</a></li>
</ul>Luis GallardoI share here another Terraform module I published as open source code, which allows you to create registries in AWS ECR.Mouse Logitech MX Anywhere 2s Flounder on Linux2020-08-05T19:00:00-05:002020-08-05T19:00:00-05:00https://lgallardo.com/2020/08/06/logitech-mx-anywhere-2s-flounder-on-linux<center><img src="/images/logitech-mouse.jpg" alt="Logitech Mx Anywhere 2s Flounder on Linux" width="340" height="340" /></center>
<p><br />
I bought a Logitech Mx Anywhere 2s Flounder mouse too free up a USB port, and be able to configure more buttons compared to the mouse I had.</p>
<p>When you connect it on Linux, the mouse works the first time without doing any magic. The two buttons on the right side of the mouse are configured for Forward and Back in the browser and any application in general.</p>
<p>For Windows and for Mac there’s a mouse software that allows you to customize these buttons (with gesture support as well), but for Linux that software is not available.</p>
<p>If you want to map these buttons in Linux you should use something like <strong>xbindkeys</strong> or <strong>xmodmap</strong>. Here I explain what I had to do to get it working the way I wanted.</p>
<h2 id="1-install-the-necessary-software">1. Install the necessary software</h2>
<p>You will need <strong>xbindkeys</strong> for maping the keys, and <strong>xdotool</strong> to execute keyboard actions.</p>
<p><code class="highlighter-rouge">apt install xbindkeys xdotool</code></p>
<h2 id="2-detecting-the-button-keys">2. Detecting the button keys</h2>
<p>You can find out what keys are associated to your mouse using <strong>xev</strong>:</p>
<p><code class="highlighter-rouge">xev | grep button</code></p>
<p>This will open a small white window which is where you should place the mouse pointer and press the buttons to obtain the values associated with each key:</p>
<center><img src="/images/xev.jpg" alt="xev" width="340" height="340" /></center>
<p><br /></p>
<p>I tried all the buttons and their corresponding values are shown above, in the first image of this post above. In total there are 9 possible buttons / keys.</p>
<h2 id="3-buttons-mapping">3. Buttons mapping</h2>
<p>You need to create a file for <strong>xbindkeys</strong> with the default options, which in fact is a file with some commented examples:</p>
<p><code class="highlighter-rouge">xbindkeys --defaults > ~/.xbindkeysrc</code></p>
<p>And then add the mapping you want. In my case I added the following in the <code class="highlighter-rouge">~/.xbindkeysrc</code>:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>"guake"
b:9
"xdotool key Super_L"
b:8
</code></pre></div></div>
<p>Finally you must run the command <code class="highlighter-rouge">xbindkeys</code>:</p>
<p><code class="highlighter-rouge">$ xbindkeys</code></p>
<p>Now pressing button 9 (Forward) will run <strong>Guake</strong>, while if I press button 8 (Back) it strokes the <code class="highlighter-rouge">Super_L</code> key (Start key or also badly known as the Windows key).</p>
<h1 id="references">References</h1>
<ul>
<li><a href="https://www.logitech.com/en-roeu/product/mx-anywhere-2s-flow.910-005153.html#specs" target="_blank">Logitech MX Anywhere 2S </a></li>
<li><a href="https://askubuntu.com/questions/101105/how-to-assign-back-and-forward-actions-to-logitech-anywhere-mouse-mx-horizo" target="_blank">How to assign “back” and “forward” actions to Logitech Anywhere Mouse MX’ horizontal scroll wheel?</a></li>
<li><a href="https://wiki.archlinux.org/index.php/Xbindkeys#Identifying_keycodes" target="_blank">Xbindkeys (ArchLinux)</a></li>
</ul>Luis GallardoI bought a Logitech Mx Anywhere 2s Flounder mouse too free up a USB port, and be able to configure more buttons compared to the mouse I had.Certified Kubernetes Administrator (CKA)2020-07-25T19:00:00-05:002020-07-25T19:00:00-05:00https://lgallardo.com/2020/11/23/certified-kubernetes-administrator-cka<center><img src="/images/ckad.jpg" alt="Certified Kubernetes Application Developer" width="340" height="340" /></center>
<p><br />
This post describes my experience and recommendations for tackling the <strong>Certified Kubernetes Administrator (CKA)</strong> exam by The Linux Foundation.</p>
<h1 id="the-exam">The exam</h1>
<p>The exam is 100% practical with about 20 questions that must be solved in 2 hours, supervised by a proctor who verifies that you are alone during the exam, and that you comply with <a href="https://docs.linuxfoundation.org/tc-docs/certification/lf-candidate-handbook/exam-rules-and-policies" target="_blank">all rules</a>. In my case, for this exam the proctored asked me to show a 360° view of the room, and to show him below my desk. He also asked me from time to time to show him my hands.</p>
<p>First off, this exam goes beyond the CKAD exam in terms of complexity. You will face more difficult challenges, like fixing a broken cluster or detecting why a service is not running properly and make it work again.</p>
<p>In my case there were few easy questions and I’d say that most of them were medium to difficult, therefore be prepared! You you must manage your time very well. Questions will be shown in a panel on the left side and you will have access to a terminal where you have to execute the commands to solve them.</p>
<center><img src="/images/exam_ui.jpg" alt="Exam UI" width="340" height="340" /></center>
<p><br /></p>
<p>There will be questions to create resources, others to identify and solve problems (troubleshooting & fixing) . You can copy and paste from the instructions, in addition to having access to a place for notes, for example to keep track of pending questions.</p>
<p>You will be able to consult the Kubernetes documentation from these sites <a href="https://kubernetes.io/docs/" target="_blank">https://kubernetes.io/docs/</a>, <a href="https://github.com/kubernetes/" target="_blank">https://github.com/kubernetes/</a>, <a href="https://kubernetes.io/blog/" target="_blank">https://kubernetes.io/blog/</a>, opening one and only one additional tab to the exam.</p>
<p>You can take the exam with Chrome, so yo can access the sites mentioned above from your bookmarks (yes, it’s allowed)</p>
<h1 id="my-experience">My experience</h1>
<p>With this exam I didn’t face any trouble at all (check my experience with CKAD exam). I didn’t have a clock or progress bar to keep track of the time in the examination interface, but this time I was conscious about timing. The proctor only interrupted me 15 minutes before the end of the exam to let me know it was almost over.</p>
<p>I went with a lot of expectations, but this time regarding the exam’s difficulty.</p>
<h1 id="how-to-prepare">How to prepare?</h1>
<p>There are several free and other paid resources, all valid to prepare, but practical experience is essential. I list some of them:</p>
<h2 id="books">Books</h2>
<ul>
<li><a href="https://www.amazon.com/gp/product/B072TS9ZQZ/ref=ppx_yo_dt_b_d_asin_title_o06?ie=UTF8&psc=1" target="_blank">The Kubernetes Book: Updated Feb 2020</a> by Nigel Poulton: This book is good for an overview of Kubernetes, and is an extension of Nigel’s course (see below).</li>
<li><a href="https://www.amazon.com/Kubernetes-Running-Dive-Future-Infrastructure-ebook/dp/B07YP1XSZ9/ref=sr_1_1?dchild=1&keywords=kubernetes+up+and+running&qid=1595782565&s=digital-text&sr=1-1" target="_blank">Kubernetes up and running</a>: This is an excellent book to learn Kubernetes, it covers various topics of CKAD and also of CKA.</li>
</ul>
<h2 id="online-courses">Online courses</h2>
<ul>
<li><a href="https://www.udemy.com/course/certified-kubernetes-application-developer/" target="_blank">Kubernetes Certified Application Developer (CKAD) with Tests (Mumshad Mannambeth)</a>: This course is very well designed and explains in detail and with many animations the concepts necessary to learn how to deploy applications in a Kubernetes cluster. Additionally, it gives access to a platform named <em><strong>Kloud Kode</strong></em> created with <em><strong>Teachable</strong></em> and with <em><strong>Katacoda</strong></em> environments designed for each topic covered, two exam-type labs (with a high degree of difficulty) and two exams to practice and prepare to work under the pressure of the real exam. .</li>
<li><a href="https://linuxacademy.com/course/certified-kubernetes-application-developer-ckad/" target="_blank">Certified Kubernetes Application Developer (CKAD) - Linux Academy</a>: If you have a LinuxAcademy subscription you can follow this course. Keep two things in mind: 1) It focuses on editing yamls and little on how to generate them. 2) The exam mocks they have to practice are not so difficult and they may be insufficient to pass without having practiced beyond them. It’s recommended to do the labs, exams and other questions to exercise (see below)</li>
<li><a href="https://acloud.guru/learn/kubernetes-deep-dive" target="_blank">Kubernetes Deep Dive - A Cloud Guru</a>: This course is to have an overview of Kubernetes, for example of its architecture (API Server, Kubelet, etc.) as well as to take the first steps in application deployments. No practical labs included.</li>
<li><a href="https://acloud.guru/learn/kubernetes-fundamental/" target="_blank">Kubernetes Fundamentals - A Cloud Guru</a>: This course is to start with Kubernetes, to have the fundamental concepts. Ideal for those who have not had contact with Kubernetes. No practical labs included.</li>
</ul>
<h2 id="practice-environments">Practice environments</h2>
<ul>
<li><a href="https://www.katacoda.com/" target="_blank">Katacoda</a>: This platform allows you to interact with a cluster with just one node, from a web console, similar to what we would get in the exam. The interesting thing is that there are scenarios created by other users that can be used to learn basic concepts, such as secrets, configmaps, volumes, etc. Please note that each scneario lasts a maximum of one hour.</li>
<li><a href="https://kubernetes.io/docs/tasks/tools/install-minikube/" target="_blank">Minikube</a>: With this option you can install a virtual machine to have your own cluster with a node.</li>
</ul>
<h2 id="exercises-to-practice">Exercises to practice</h2>
<ul>
<li><a href="https://github.com/dgkanatsios/CKAD-exercises" target="_blank">CKAD Exercises</a>:
A set of exercises that will help you prepare for the exam and can also help you learn and practice with Kubernetes.</li>
<li><a href="https://medium.com/bb-tutorials-and-thoughts/practice-enough-with-these-questions-for-the-ckad-exam-2f42d1228552" target="_blank">Practice Enough With These 150 Questions for the CKAD Exam</a>:This is another set of exercises that serve to prepare you and have all the concepts fresh before going to the exam..</li>
<li><a href="https://codeburst.io/kubernetes-ckad-weekly-challenges-overview-and-tips-7282b36a2681" target="_blank">Kubernetes CKAD Example Exam Questions Practical Challenge Series</a>: This page presents some challenges to complete and some tips for the exam. They also offer an exam simulator at a cost of €30 (I didn’t subscribe, so I don’t know exactly what the simulator is like or if it really has similar exam questions).</li>
</ul>
<h1 id="endnotes">Endnotes</h1>
<p>Again I recommend you to practice enough before taking the exam, even if you have experience with Kubernetes. Time management is important, so you must be prepared to use the Kubernetes documentation quickly (from the documentation page or from the console with kubectl), be prepared to generate yamls (not edit them), and handle nerves and pressure.</p>
<h1 id="references">References</h1>
<ul>
<li><a href="https://docs.linuxfoundation.org/tc-docs/certification/lf-candidate-handbook/exam-rules-and-policies" target="_blank">Exam Rules and Policies</a></li>
<li><a href="https://www.amazon.com/gp/product/B072TS9ZQZ/ref=ppx_yo_dt_b_d_asin_title_o06?ie=UTF8&psc=1" target="_blank">The Kubernetes Book: Updated Feb 2020</a> by Nigel Poulton.</li>
<li><a href="https://www.amazon.com/Kubernetes-Running-Dive-Future-Infrastructure-ebook/dp/B07YP1XSZ9/ref=sr_1_1?dchild=1&keywords=kubernetes+up+and+running&qid=1595782565&s=digital-text&sr=1-1" target="_blank">Kubernetes up and running</a></li>
<li><a href="https://www.udemy.com/course/certified-kubernetes-application-developer/" target="_blank">Kubernetes Certified Application Developer (CKAD) with Tests (Mumshad Mannambeth)</a></li>
<li><a href="https://linuxacademy.com/course/certified-kubernetes-application-developer-ckad/" target="_blank">Certified Kubernetes Application Developer (CKAD) - Linux Academy</a></li>
<li><a href="https://acloud.guru/learn/kubernetes-deep-dive" target="_blank">Kubernetes Deep Dive - A Cloud Guru</a></li>
<li><a href="https://acloud.guru/learn/kubernetes-fundamental/" target="_blank">Kubernetes Fundamentals - A Cloud Guru</a></li>
<li><a href="https://www.katacoda.com/" target="_blank">Katacoda</a></li>
<li><a href="https://kubernetes.io/docs/tasks/tools/install-minikube/" target="_blank">Minikube</a></li>
<li><a href="https://github.com/dgkanatsios/CKAD-exercises" target="_blank">CKAD Exercises</a></li>
<li><a href="https://medium.com/bb-tutorials-and-thoughts/practice-enough-with-these-questions-for-the-ckad-exam-2f42d1228552" target="_blank">Practice Enough With These 150 Questions for the CKAD Exam</a></li>
<li><a href="https://codeburst.io/kubernetes-ckad-weekly-challenges-overview-and-tips-7282b36a2681" target="_blank">Kubernetes CKAD Example Exam Questions Practical Challenge Series</a></li>
</ul>Luis GallardoThis post describes my experience and recommendations for tackling the Certified Kubernetes Administrator (CKA) exam by The Linux Foundation.Certified Kubernetes Application Developer (CKAD)2020-07-25T19:00:00-05:002020-07-25T19:00:00-05:00https://lgallardo.com/2020/07/26/certified-kubernetes-application-developer-ckad<center><img src="/images/ckad.jpg" alt="Certified Kubernetes Application Developer" width="340" height="340" /></center>
<p><br />
I recently approved the <strong>Certified Kubernetes Application Developer (CKAD)</strong> exam by The Linux Foundation, so I decided to share my experience and some recommendations to prepare for the exam.</p>
<h1 id="the-exam">The exam</h1>
<p>The exam is 100% practical with 19 questions that must be solved in 2 hours, supervised by a proctor who verifies that you are alone during the exam, and that you comply with <a href="https://docs.linuxfoundation.org/tc-docs/certification/lf-candidate-handbook/exam-rules-and-policies" target="_blank">all rules</a> (for example in my case he asked me to close all doors that gave access to my dining room, where I took the exam).</p>
<p>Some questions will be easy, others will have several steps to follow, so you must manage your time very well. Questions will be shown in a panel on the left side and you will have access to a terminal where you must execute the commands to solve them.</p>
<center><img src="/images/exam_ui.jpg" alt="Exam UI" width="340" height="340" /></center>
<p><br /></p>
<p>There will be questions to create resources and others to identify and solve problems (troubleshooting). You can copy and paste from the instructions, in addition to having access to a place for notes, for example to keep track of pending questions.</p>
<p>You will be able to consult the Kubernetes documentation from these sites <a href="https://kubernetes.io/docs/" target="_blank">https://kubernetes.io/docs/</a>, <a href="https://github.com/kubernetes/" target="_blank">https://github.com/kubernetes/</a>, <a href="https://kubernetes.io/blog/" target="_blank">https://kubernetes.io/blog/</a>, opening one and only one additional tab to the exam.</p>
<p>You can take the exam with Chrome, so yo can access the sites mentioned above from your bookmarks (yes, it’s allowed)</p>
<h1 id="my-experience">My experience</h1>
<p>I had some expectation because it’s a practical exam, and since it was the first of this style that I took, I didn’t know what to expect or how I was going to be able to handle time.</p>
<p>During the exam, several things happened to me that delayed me, for example, when I used a Vim’s key combination to move between windows, I accidentally closed the exam, so I had to reconnect and contact the proctor.</p>
<p>On the other hand, that day my Internet provider had problems and made my connection very slow, so changes in the yaml files were seen with delays of approximately 5 seconds.</p>
<p>At some point the connection was completely lost, and the exam was closed, so I had to log in again and coordinate with the proctor.</p>
<p>Another thing that happened was that the alarm on my nearby cell phone went off (I took the exam at 5:00 AM) so I asked the proctor for permission to turn it off, therefore he had to pause the exam.</p>
<p>All these disconnections and pauses don’t stop the time, when the exam begins you have exactly 2 hours.
exactas.</p>
<p>Another drawback I had was that I did not have a clock to keep track of the time in the examination interface, but rather a progress bar that was sometimes missing, so the proctor reminded me of the remaining time every so often, interrupting my concentration.</p>
<h1 id="how-to-prepare">How to prepare?</h1>
<p>There are several free and other paid resources, all valid to prepare, but practical experience is essential. I list some of them:</p>
<h2 id="books">Books</h2>
<ul>
<li><a href="https://www.amazon.com/gp/product/B072TS9ZQZ/ref=ppx_yo_dt_b_d_asin_title_o06?ie=UTF8&psc=1" target="_blank">The Kubernetes Book: Updated Feb 2020</a> by Nigel Poulton: This book is good for an overview of Kubernetes, and is an extension of Nigel’s course (see below).</li>
<li><a href="https://www.amazon.com/Kubernetes-Running-Dive-Future-Infrastructure-ebook/dp/B07YP1XSZ9/ref=sr_1_1?dchild=1&keywords=kubernetes+up+and+running&qid=1595782565&s=digital-text&sr=1-1" target="_blank">Kubernetes up and running</a>: This is an excellent book to learn Kubernetes, it covers various topics of CKAD and also of CKA.</li>
</ul>
<h2 id="online-courses">Online courses</h2>
<ul>
<li><a href="https://www.udemy.com/course/certified-kubernetes-application-developer/" target="_blank">Kubernetes Certified Application Developer (CKAD) with Tests (Mumshad Mannambeth)</a>: This course is very well designed and explains in detail and with many animations the concepts necessary to learn how to deploy applications in a Kubernetes cluster. Additionally, it gives access to a platform named <em><strong>Kloud Kode</strong></em> created with <em><strong>Teachable</strong></em> and with <em><strong>Katacoda</strong></em> environments designed for each topic covered, two exam-type labs (with a high degree of difficulty) and two exams to practice and prepare to work under the pressure of the real exam. .</li>
<li><a href="https://linuxacademy.com/course/certified-kubernetes-application-developer-ckad/" target="_blank">Certified Kubernetes Application Developer (CKAD) - Linux Academy</a>: If you have a LinuxAcademy subscription you can follow this course. Keep two things in mind: 1) It focuses on editing yamls and little on how to generate them. 2) The exam mocks they have to practice are not so difficult and they may be insufficient to pass without having practiced beyond them. It’s recommended to do the labs, exams and other questions to exercise (see below)</li>
<li><a href="https://acloud.guru/learn/kubernetes-deep-dive" target="_blank">Kubernetes Deep Dive - A Cloud Guru</a>: This course is to have an overview of Kubernetes, for example of its architecture (API Server, Kubelet, etc.) as well as to take the first steps in application deployments. No practical labs included.</li>
<li><a href="https://acloud.guru/learn/kubernetes-fundamental/" target="_blank">Kubernetes Fundamentals - A Cloud Guru</a>: This course is to start with Kubernetes, to have the fundamental concepts. Ideal for those who have not had contact with Kubernetes. No practical labs included.</li>
</ul>
<h2 id="practice-environments">Practice environments</h2>
<ul>
<li><a href="https://www.katacoda.com/" target="_blank">Katacoda</a>: This platform allows you to interact with a cluster with just one node, from a web console, similar to what we would get in the exam. The interesting thing is that there are scenarios created by other users that can be used to learn basic concepts, such as secrets, configmaps, volumes, etc. Please note that each scneario lasts a maximum of one hour.</li>
<li><a href="https://kubernetes.io/docs/tasks/tools/install-minikube/" target="_blank">Minikube</a>: With this option you can install a virtual machine to have your own cluster with a node.</li>
</ul>
<h2 id="exercises-to-practice">Exercises to practice</h2>
<ul>
<li><a href="https://github.com/dgkanatsios/CKAD-exercises" target="_blank">CKAD Exercises</a>:
A set of exercises that will help you prepare for the exam and can also help you learn and practice with Kubernetes.</li>
<li><a href="https://medium.com/bb-tutorials-and-thoughts/practice-enough-with-these-questions-for-the-ckad-exam-2f42d1228552" target="_blank">Practice Enough With These 150 Questions for the CKAD Exam</a>:This is another set of exercises that serve to prepare you and have all the concepts fresh before going to the exam..</li>
<li><a href="https://codeburst.io/kubernetes-ckad-weekly-challenges-overview-and-tips-7282b36a2681" target="_blank">Kubernetes CKAD Example Exam Questions Practical Challenge Series</a>: This page presents some challenges to complete and some tips for the exam. They also offer an exam simulator at a cost of €30 (I didn’t subscribe, so I don’t know exactly what the simulator is like or if it really has similar exam questions).</li>
</ul>
<h1 id="endnotes">Endnotes</h1>
<p>Again I recommend you to practice enough before taking the exam, even if you have experience with Kubernetes. Time management is important, so you must be prepared to use the Kubernetes documentation quickly (from the documentation page or from the console with kubectl), be prepared to generate yamls (not edit them), and handle nerves and pressure.</p>
<h1 id="references">References</h1>
<ul>
<li><a href="https://docs.linuxfoundation.org/tc-docs/certification/lf-candidate-handbook/exam-rules-and-policies" target="_blank">Exam Rules and Policies</a></li>
<li><a href="https://www.amazon.com/gp/product/B072TS9ZQZ/ref=ppx_yo_dt_b_d_asin_title_o06?ie=UTF8&psc=1" target="_blank">The Kubernetes Book: Updated Feb 2020</a> by Nigel Poulton.</li>
<li><a href="https://www.amazon.com/Kubernetes-Running-Dive-Future-Infrastructure-ebook/dp/B07YP1XSZ9/ref=sr_1_1?dchild=1&keywords=kubernetes+up+and+running&qid=1595782565&s=digital-text&sr=1-1" target="_blank">Kubernetes up and running</a></li>
<li><a href="https://www.udemy.com/course/certified-kubernetes-application-developer/" target="_blank">Kubernetes Certified Application Developer (CKAD) with Tests (Mumshad Mannambeth)</a></li>
<li><a href="https://linuxacademy.com/course/certified-kubernetes-application-developer-ckad/" target="_blank">Certified Kubernetes Application Developer (CKAD) - Linux Academy</a></li>
<li><a href="https://acloud.guru/learn/kubernetes-deep-dive" target="_blank">Kubernetes Deep Dive - A Cloud Guru</a></li>
<li><a href="https://acloud.guru/learn/kubernetes-fundamental/" target="_blank">Kubernetes Fundamentals - A Cloud Guru</a></li>
<li><a href="https://www.katacoda.com/" target="_blank">Katacoda</a></li>
<li><a href="https://kubernetes.io/docs/tasks/tools/install-minikube/" target="_blank">Minikube</a></li>
<li><a href="https://github.com/dgkanatsios/CKAD-exercises" target="_blank">CKAD Exercises</a></li>
<li><a href="https://medium.com/bb-tutorials-and-thoughts/practice-enough-with-these-questions-for-the-ckad-exam-2f42d1228552" target="_blank">Practice Enough With These 150 Questions for the CKAD Exam</a></li>
<li><a href="https://codeburst.io/kubernetes-ckad-weekly-challenges-overview-and-tips-7282b36a2681" target="_blank">Kubernetes CKAD Example Exam Questions Practical Challenge Series</a></li>
</ul>Luis GallardoI recently approved the Certified Kubernetes Application Developer (CKAD) exam by The Linux Foundation, so I decided to share my experience and some recommendations to prepare for the exam.Terraform module for Secrets Manager2020-06-25T19:00:00-05:002020-06-25T19:00:00-05:00https://lgallardo.com/2020/06/26/terraform-module-for-amazon-secrets-manager<center><img src="/images/terraform-aws-secrets-manager.jpg" alt="AWS Secrets Manager" /></center>
<p><br />
I just published a Terraform module called <strong>terraform-aws-secrets-manager</strong> at Github, so I decided to share it as well in the public Terraform Registry.</p>
<p>You can check the module <strong>terraform-aws-secrets-manager</strong> at the <a href="https://registry.terraform.io/modules/lgallard/secrets-manager/aws/" target="_blank">Terraform Registry</a> or clone it from <a href="https://github.com/lgallard/terraform-aws-secrets-manager" target="_blank">Github</a>.</p>
<p>If you want to take a sneak of the module, I also left the README in this post:</p>
<p><img src="https://lgallardo.com/images/terraform.jpg" alt="Terraform" /></p>
<h1 id="terraform-aws-secrets-manager">terraform-aws-secrets-manager</h1>
<p>Terraform module to create <a href="https://aws.amazon.com/secrets-manager/" target="_blank">Amazon Secrets Manager</a> resources.</p>
<p>AWS Secrets Manager helps you protect secrets needed to access your applications, services, and IT resources. The service enables you to easily rotate, manage, and retrieve database credentials, API keys, and other secrets throughout their lifecycle.</p>
<h2 id="examples">Examples</h2>
<p>Check the <a href="https://github.com/lgallard/terraform-aws-secrets-manager/tree/master/examples/" target="_blank">examples</a> folder where you can see the complete compilation of snippets.</p>
<h2 id="usage">Usage</h2>
<p>You can create secrets for plain texts, keys/values and binary data:</p>
<h3 id="plain-text-secrets">Plain text secrets</h3>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>module "secrets-manager-1" {
source = "lgallard/secrets-manager/aws"
secrets = [
{
name = "secret-1"
description = "My secret 1"
recovery_window_in_days = 7
secret_string = "This is an example"
},
{
name = "secret-2"
description = "My secret 2"
recovery_window_in_days = 7
secret_string = "This is another example"
}
]
tags = {
Owner = "DevOps team"
Environment = "dev"
Terraform = true
}
}
</code></pre></div></div>
<h3 id="keyvalue-secrets">Key/Value secrets</h3>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>module "secrets-manager-2" {
source = "lgallard/secrets-manager/aws"
secrets = [
{
name = "secret-kv-1"
description = "This is a key/value secret"
secret_key_value = {
key1 = "value1"
key2 = "value2"
}
recovery_window_in_days = 7
},
{
name = "secret-kv-2"
description = "Another key/value secret"
secret_key_value = {
username = "user"
password = "topsecret"
}
tags = {
app = "web"
}
recovery_window_in_days = 7
},
]
tags = {
Owner = "DevOps team"
Environment = "dev"
Terraform = true
}
}
</code></pre></div></div>
<h3 id="binary-secrets">Binary secrets</h3>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>module "secrets-manager-3" {
source = "lgallard/secrets-manager/aws"
secrets = [
{
name = "secret-binary-1"
description = "This is a binary secret"
secret_binary = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDt4TcI58h4G0wR+GcDY+0VJR10JNvG92jEKGaKxeMaOkfsXflVGsYXbfVBBCG/n3uHtTse7baYLB6LWQAuYWL1SHJVhhTQ7pPiocFWibAvJlVo1l7qJEDu2OxKpWEleCE+p3ufNXAy7v5UFO7EOnj0Zg6R3F/MiAWbQnaEHcYzNtogyC24YBecBLrBXZNi1g0AN1hM9k+3XvWUYTf9vPv8LIWnqo7y4Q2iEGWWurf37YFl1LzX4mG/Co+Vfe5TlZSe2YPMYWlw0ZKaKvwzInRR6dPMAflo3ABzlduiIbSdp110uGqB8i2M8eGXNDxR7Ni4nnLWnT9r1cpWhXWP6pAG4Xg8+x7+PIg/pgjgJNmsURw+jPD6+hkCw2Vz16EIgkC2b7lj0V6J4LncUoRzU/1sAzCQ4tspy3SKBUinYoxbDvXleF66FHEjfparnvNwfslBx0IJjG2uRwuX6zrsNIsGF1stEjz+eyAOtFV4/wRjRcCNDZvl1ODzIvwf8pAWddE= lgallard@server1"
},
{
name = "secret-binary-2"
description = "Another binary secret"
secret_binary = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCzc818NSC6oJYnNjVWoF43+IuQpqc3WyS8BWZ50uawK5lY/aObweX2YiXPv2CoVvHUM0vG7U7BDBvNi2xwsT9n9uT27lcVQsTa8iDtpyoeBhcj3vJ60Jd04UfoMP7Og6UbD+KGiaqQ0LEtMXq6d3i619t7V0UkaJ4MXh2xl5y3bV4zNzTXdSScJnvMFfjLW0pJOOqltLma3NQ9ILVdMSK2Vzxc87T+h/jp0VuUAX4Rx9DqmxEU/4JadXmow/BKy69KVwAk/AQ8jL7OwD2YAxlMKqKnOsBJQF27YjmMD240UjkmnPlxkV8+g9b2hA0iM5GL+5MWg6pPUE0BYdarCmwyuaWYhv/426LnfHTz9UVC3y9Hg5c4X4I6AdJJUmarZXqxnMe9jJiqiQ+CAuxW3m0gIGsEbUul6raG73xFuozlaXq3J+kMCVW24eG2i5fezgmtiysIf/dpcUo+YLkX+U8jdMQg9IwCY0bf8XL39kwJ7u8uWU8+7nMcS9VQ5llVVMk= lgallard@server2"
recovery_window_in_days = 7
tags = {
app = "web"
}
}
]
tags = {
Owner = "DevOps team"
Environment = "dev"
Terraform = true
}
}
</code></pre></div></div>
<h2 id="secrets-rotation">Secrets Rotation</h2>
<p>If yo need to rotate your secrets, use <code class="highlighter-rouge">rotate_secrets</code> list to define them. Take into account that the lambda function must exist and it must have the right permissions to rotate the secrets in AWS Secret manager:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>module "secrets-manager-4" {
source = "lgallard/secrets-manager/aws"
rotate_secrets = [
{
name = "secret-rotate-1"
description = "This is a secret to be rotated by a lambda"
secret_string = "This is an example"
rotation_lambda_arn = "arn:aws:lambda:us-east-1:123455678910:function:lambda-rotate-secret"
recovery_window_in_days = 15
},
{
name = "secret-rotate-2"
description = "This is another secret to be rotated by a lambda"
secret_string = "This is another example"
rotation_lambda_arn = "arn:aws:lambda:us-east-1:123455678910:function:lambda-rotate-secret"
recovery_window_in_days = 7
},
]
tags = {
Owner = "DevOps team"
Environment = "dev"
Terraform = true
}
}
</code></pre></div></div>
<h2 id="several-secret-definitions">Several secret definitions</h2>
<p>You can define different type of secrets (string, key/balue or binary) in the same <code class="highlighter-rouge">secrets</code> or <code class="highlighter-rouge">rotate_secrets</code> list:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>module "secrets-manager-5" {
source = "lgallard/secrets-manager/aws"
secrets = [
{
name = "secret-plain"
description = "My plain text secret"
recovery_window_in_days = 7
secret_string = "This is an example"
},
{
name = "secret-key-value"
description = "This is a key/value secret"
secret_key_value = {
username = "user"
password = "topsecret"
}
tags = {
app = "web"
}
recovery_window_in_days = 7
},
]
tags = {
Owner = "DevOps team"
Environment = "dev"
Terraform = true
}
}
</code></pre></div></div>
<h2 id="providers">Providers</h2>
<table>
<thead>
<tr>
<th>Name</th>
<th>Version</th>
</tr>
</thead>
<tbody>
<tr>
<td>aws</td>
<td>n/a</td>
</tr>
</tbody>
</table>
<h2 id="inputs">Inputs</h2>
<table>
<thead>
<tr>
<th>Name</th>
<th>Description</th>
<th>Type</th>
<th>Default</th>
<th style="text-align: center">Required</th>
</tr>
</thead>
<tbody>
<tr>
<td>automatically_after_days</td>
<td>Specifies the number of days between automatic scheduled rotations of the secret.</td>
<td><code class="highlighter-rouge">number</code></td>
<td><code class="highlighter-rouge">30</code></td>
<td style="text-align: center">no</td>
</tr>
<tr>
<td>recovery_window_in_days</td>
<td>Specifies the number of days that AWS Secrets Manager waits before it can delete the secret. This value can be 0 to force deletion without recovery or range from 7 to 30 days.</td>
<td><code class="highlighter-rouge">number</code></td>
<td><code class="highlighter-rouge">30</code></td>
<td style="text-align: center">no</td>
</tr>
<tr>
<td>rotate_secrets</td>
<td>List of secrets to keep and rotate in AWS Secrets Manager</td>
<td><code class="highlighter-rouge">any</code></td>
<td><code class="highlighter-rouge">[]</code></td>
<td style="text-align: center">no</td>
</tr>
<tr>
<td>secrets</td>
<td>List of secrets to keep in AWS Secrets Manager</td>
<td><code class="highlighter-rouge">any</code></td>
<td><code class="highlighter-rouge">[]</code></td>
<td style="text-align: center">no</td>
</tr>
<tr>
<td>tags</td>
<td>Specifies a key-value map of user-defined tags that are attached to the secret.</td>
<td><code class="highlighter-rouge">any</code></td>
<td><code class="highlighter-rouge">{}</code></td>
<td style="text-align: center">no</td>
</tr>
</tbody>
</table>
<h2 id="outputs">Outputs</h2>
<table>
<thead>
<tr>
<th>Name</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>rotate_secret_arns</td>
<td>Rotate secret arn list</td>
</tr>
<tr>
<td>rotate_secret_ids</td>
<td>Rotate secret id list</td>
</tr>
<tr>
<td>secret_arns</td>
<td>Secret arn list</td>
</tr>
<tr>
<td>secret_ids</td>
<td>Secret id list</td>
</tr>
</tbody>
</table>
<h2 id="references">References</h2>
<ul>
<li><a href="https://github.com/lgallard/terraform-aws-secrets-manager.git" target="_blank">terraform-aws-secrets-manager module at github</a></li>
<li><a href="https://registry.terraform.io/modules/lgallard/secrets-manager/aws/" target="_blank">terraform-aws-secrets-manager module at Terraform registry</a></li>
</ul>Luis GallardoI just published a Terraform module called terraform-aws-secrets-manager at Github, so I decided to share it as well in the public Terraform Registry.