Articles

Slackware & Qemu - Part 2: Rust vs Ansible

Interesting title, isn't it ? How Rust can be compared with Ansible ? System langugage vs infrastructure tool ? Well, it can as long as they are used in the same manner. And believe, they can be used in the same manner. So where did I get the idea to use Rust as a configuration language ? Well, it all started with using Ansible throughout the several years now. It's really nice tool, with good idea to it, it has it's bad sides, but overall it's been around for years and most likely will be for years to come. However, something which seemed like a bad design, was lack of backwards compatibility with constantly changing modules. One of the reasons might be it's based on Python, which is changing pretty fast, so there is no chance to keep everything compatibile. But back to my reasons - there was a year, when I was working with Zabbix and I was using Ansible to configure it. Sure, it was nice (at the time of that there was no items module, which was bad enough), quite fast and get done (mostly) what I wanted. And then items module were added - what a blast ! I figured, they almost won it for me. So I configured Zabbix, get back to my other DevOps tasks and way to go. Several months later, new guy come to assist, and he's asking whether we are using Ansible, so my answer was: yes, be my guest, there are the playbooks. And what a surprise was, when I found out, Ansible changed core module responsible for Zabbix auth ! All my playbooks needed to be rewritten. I was really surprised, as this was suboptimal solution to say the least. When it comes to Zabbix itself in Ansible territory, they made a strange decision - SSH into Zabbix machine, so API calls can be send to localhost (?!). Zabbix API is one of the good things about it, especially when you can generate token and use it to calls, without storing it, so there is no need to SSH as this add another layer and time to execution.
    So after some time, getting into more Rust I figured - why not use Rust to configure system ? It should be faster and compatibile enough with what you are writing. Well, let's try it out. First let's see if there are any crates that covers absolute basics in SysOps work - SSH. And there are few ! Nice. So I've checked and choice of mine was to use russh, which is currently maintained and have different kind's of session - whether it's interactive or not. Seemed like a bit advanced start into this adventure, as syntax is not super easy, but after trial and error I got where I needed.
    I've prepared 10 VM's (check my other post) with 1 CPU/512 MB Ram and started test. First one was:
1. Execute 3 simple commands (ls -la, df -h, touch file.test) in one session:
    a) Ansible (with skipping all unnecessary steps) - ~45s
    b) Rust (debug build binary) - ~16s
2. Execute 3 above commands in separate sessions:
    a) Ansible - ~1m40s,
    b) Rust - ~45s
So as you can see, Rust have clear advantage, being ~50% - ~60% faster then Ansible. And that's being performed on local network with ping less than 0.1ms ! Further tests will come soon.
    In summary, sure, Rust has "steep learning curve", especially at the beginning, but it's well worth it - time of execution and it's modularity. It's build for reliability and execution time, so with infrastructure at scale might become more crucial as the time will go on. It's worth to try. You can try it yourself by using devops-armory library from crates.io, which is using TOML file as source of information. 

Slackware & Qemu

    Lately I've been trying to get working Slackware with special use case - creating VM. This purpose become not so easy to achieve, as Slackware has peculiar way of implementing modern solutions into system itself. First choice was to get Xen working, but after trial and error I've was able to compile, start and load Xen modules in proper kernel and create base of VM. Not bad, but eventually I came up short and haven't finished task as I wanted. Well...system does work, so does network, but I needed something actually running VM, so I switched to Qemu. 
    After finding some interesting articles about it, and tweaking after some excercise I was able to run VM. Here comes special thanks to VMS package author as it will take the most of heavy lifting for you, has nice config template and quite nice documentation. In manual it says you need several packages, so here road might become a bit bumpy, as some of them I've installed via slackpkg and some of them via slackbuilds.org (sbotools). Fun fact - I've tried it on 2 Linux hosts, both current and latest (October) was much easier to cooperate than the older one (June), so I needed mix both methods to get all necessary dependencies on board. After that, getting VMS from slackbuilds.org is a real breeze. Rock N Roll ! So I've prepared VM (according to docs in the VMS), installed entire Slackware inside VM without problems. It took some time, as I'm using 1 CPU with 512MB Ram (custom use case, as I need it for further development, multiplied by 10 so that will consume 10 CPU/Threads with >5GB Ram, and I need to run it on my server machine). I've started the VM, trimmed it a bit as I don't need now all the packages (rust, ruby, perl, php, mariadb have been removed) - result is 7.7GB used by system against ~10GB image size. That will need further trim to get below 5GB of system use. It might seem a bit much, but it has all tools I'm using on a daily basis, and we will see how it behave in cloud environment. 
    A bit of context here - The main reason of me getting into this venture, were problems with legacy systems on cloud VM's. These can become real pain when it comes to maintenance, especially system upgrade. Slackware never disappointed in that matter, even after several years with non updated system it still didn't show any problems. Actually I've tried to update from 14.1 (I've got one really old laptop) to current, and it went without any problems. Sure, it's good to remember to upgrade slackpkg first, before the rest of the steps but that's all documented now. Docs by the way are getting better and better. 
    Back to business. I was finally able to:
1. Configure VM - check
2. Run VM - check
3. Trim system inside VM - check.
    Nice, I'm on a good road. 2 things left - how to run it in headless mode, then how to configure network so I can actually use it in headless mode. Running it without monitor was a bit of challenge, as most of internet posts are pointing into "non graphical options" and it has some use case, however not when you're not logged into X (graphical interface). So after getting several "gtk errors" I found a package to run VM in gtk-emulated state (search phrase: "how to run qemu vm without GTK ?"). Of course, slackbuilds.org do not disappoint in that matter as well - there is prepared package to get you going: ... and you just use it in prompt before vms command: ... . Isn't that great ? But one more thing left to do: networking. And that was a bit of hiccup, as I didn't want to bridge everything, so I decided to do some oldschool routing instead. That would eventually became a bit of pain, but somebody come to rescue us all - AlienBob. I found his script and modify one part only (regarding DNSMASQ). I've also used vde2 which starts tap interface with proper networking, but DNSMASQ is used to act as a DHCP server. So what actually was left to do ?  Yes, you're right - ip_forwarding, but guess what - Slackware got that covered, so I've just started /etc/rc.d/rc.ip_forward and all is working as expected. I've got my VM on isolated network and my local devices has access to it. And that is just a prelude to another part.
    To be continued...

DevOps Adventures…Log parser – Downloading Logs

 

DevOps Adventures...Log parser – Downloading Logs

 

 

 

When we have plan how to download logs, we can move to downloading itself. For such purpose we will need the following:

 

 

 

1. k8s endpoint

 

2. service account with token

 

3. cluster role + role binding

 

4. reqwest library

 

 

 

To download logs (considering we have everything set up) we simply send GET request for specific endpoint:

 

 

 

https://${CLUSTER_IP}/api/v1/namespaces/${NAMESPACE}/pods/{hostname}/log?&tailLines=10&follow&timestamps=true

 

 

 

Above URL gives us access to logs which additonally consists timestamp. But before we get there, we need something more:

 

 

 

https://${CLUSTER_IP}/api/v1/namespaces/${NAMESPACE}/pods/

 

 

 

Above URL gives us possibility to list pods for specific namespace. We will need this, since in real life scenario, especially in production environments there are more pods than 1 in specific namespace. So in simple terms we will need construction like this: for each pod in specific namespace, download log with timestamp.

 

 

 

For now, this configuration gives us insight into logs in real time, which are printed into console output.

 

Automate with Kubectl, Bash and CRON.

Lately I've stumbled upon requirement - get data from pod and put it into cloud storage. Looked simple enough, so I got into it straight away.
    Nothing fancy from infra side:

bastion -> k8s -> bastion -> tar data -> gcs.

    To accomplish that, we will need several things, like proper access to k8s cluster, so I started with getting proper rights to access cluster. There are at least several ways how to do it, but I decided to go with ServiceAccount. This approach works ok, it gives some flexibility in modifying access control further down the line (in case if it's needed). When I've set it up, I've moved to installing packages which are necessary
1. gcloud - to log in to google resources
2. kubectl - to interact with k8s cluster
3. gsutil - to send data to GCS
4. gcloud-auth-plugin - to authorize access to GKE.
    So far so good.
    After above, I've started to write a bash script, which simple enough looked something like below:

#!/bin/bash

CURRENT_DATE=`date -I`

GCS=$BUCKET_NAME

echo "Activating proper service account..."
gcloud auth activate-service-account --key-file=$PATH_TO_YOUR_SA
gcloud container clusters get-credentials $CLUSTER_NAME --region $REGION --project $PROJECT

echo "Copying data into local folder..."
/home/$USER/google-cloud-sdk/bin/kubectl cp namespace/pod-name:/data local-data/

echo "Packing data..."
tar czf backup-data-${CURRENT_DATE}.tar.gz local-data/

echo "Sending data to gcs..."
gcloud storage cp backup-data-${CURRENT_DATE}.tar.gz gs://${GCS}

echo "Removing dumps ..."
rm local-data/*
rm backup-data-${CURRENT_DATE}.tar.gz

echo "Finished ! ${CURRENT_DATE}"

So after that, i've just made my script executable via simple chmod +x script_name.sh and started testing from console. It works as expected, so happy days. Just one more thing to modify - CRON, and voilla. I've just modified crontab via crontab -e and that was it - set proper time when script needs to be executed and we're done ! ... well, not exactly. I've looked next day and script worked as well as cron, but the archive was...empty. Why ? Well, due to several factors which are not so easy to figure out. First thing which I've missed, was gke executables are not in the default $PATH, hence script run from cron was just not executing them, not kubectl anyway. Ok,I figured that I'll put absolute path to the executable. Still no joy ! But why ? That's due some inconsistency on kubectl side. Trhrough trial and error I finally managed to fiind some clues and resolve the problem. That's how it progressed. First, I've put test script to check why kubectl is not executing, so I've written something like this and put it into cron:

#!/bin/bash

echo "Activating proper service account..."
gcloud auth ...
gcloud container ...

echo "Get pods lists for ..."
/home/$USER/google-cloud-sdk/bin/kubectl get pods  -n namespace 2>&1  > /home/$USER/test.log

Execute it and...Fail ! It throws error about passing arguments in wrong order. This is very strange, as executing it from console works fine. I figured that only reasonable workaround would be to move namespace section before getting pods like that:

/home/$USER/google-cloud-sdk/bin/kubectl -n namespace  get pods  2>&1  > /home/$USER/test.log

and it worked. Ok...strange behaviour, but whatever, let's get to the point how to fix main script. I've applied the same to the prototype, and guess what - still doesn't work ! Ok...so I've moved to another debugging via 2>&1  and it happened, that gke plugin is not found nor installed ! Another mystery, so I've finally added google-sdk executable dir into $PATH via:

export PATH="/home/$USER/google-cloud-sdk/bin:$PATH"

and it worked, as it should. All required data is being downloaded to local directory and uploaded to GCS.

DevOps Adventures…Log parser – Authentication

 

How to even start collecting logs from kubernetes ? Through access to proper endpoint, and this one is served by kubernetes API. Endpoint list can be found here:

 

 

 

https://jamesdefabia.github.io/docs/api-reference/v1/operations/

 

 

 

To access necessary endpoint, we need external endpoint address, which is external kubernetes IP cluster. When we know from where we can gather all logs, we have to keep in mind, that kubernetes API access is available only via token, which we have to send in header. Interesting hint – according to documentation, token is generated automatically during namespace generation in k8s scope – it is hidden as secret as ServiceAccount. That’s a big plus. However it doesn’t give us straight away access to all resources, which we need. So to get above access, we need to create ClusterRole and RoleBinding, which will grant us access to required resources. After applying changes to k8s, we don’t have to do anything beside it. It’s available instantly. That’s all when it comes to k8s.

 

 

 

When it comes to Rust side, I’ve decided to choose awc library, which uses another library under the hood – reqwest. It is helpful as much as it simplify communications to cluster which uses HTTPS protocol, and cert checking can be easily disabled. When it comes to different libraries, they were easier to read, but more difficult to actual use, as they didn’t work as I would like to – I was unable to create automatically token to access k8s cluster. Nonetheless, I aws able to create token manually for specific ServiceAccount and it works very well. Important thing to remember - token for specific ServiceAccount works only for specific namespace ! So every namespace will require separate token, thus separate function which will handle the connection.

 

Who's online

We have 3 guests and no members online

Statistics

Visitors
1
Articles
56
Articles View Hits
168969
2012. Powered by Morgul 2012-2022
Download Joomla Templates