diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml index 9fd0f6b..c49533b 100644 --- a/.github/workflows/docker-image.yml +++ b/.github/workflows/docker-image.yml @@ -1,10 +1,10 @@ name: Docker Image CI on: - push: - tags: - - '*' - workflow_dispatch: + push: + tags: + - "*" + workflow_dispatch: env: CARGO_TERM_COLOR: always @@ -13,26 +13,26 @@ jobs: build-container: runs-on: ubuntu-latest steps: - - name: Check out the repo - uses: actions/checkout@v3 - - - name: Log in to Docker Hub - uses: docker/login-action@f4ef78c080cd8ba55a85445d5b36e214a81df20a - with: - username: ${{ secrets.DOCKER_USERNAME }} - password: ${{ secrets.DOCKER_PASSWORD }} - - - name: Extract metadata (tags, labels) for Docker - id: meta - uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7 - with: - images: alexohneander/alexohneander-astro - - - name: Build and push Docker image - uses: docker/build-push-action@3b5e8027fcad23fda98b2e3ac259d8d67585f671 - with: - context: . - file: ./Dockerfile - push: true - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} + - name: Check out the repo + uses: actions/checkout@v3 + + - name: Log in to Docker Hub + uses: docker/login-action@f4ef78c080cd8ba55a85445d5b36e214a81df20a + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7 + with: + images: alexohneander/alexohneander-astro + + - name: Build and push Docker image + uses: docker/build-push-action@3b5e8027fcad23fda98b2e3ac259d8d67585f671 + with: + context: . + file: ./Dockerfile + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} diff --git a/src/components/Header.astro b/src/components/Header.astro index ec5f8ba..5f8a50f 100644 --- a/src/components/Header.astro +++ b/src/components/Header.astro @@ -69,7 +69,10 @@ const { activeNav } = Astro.props;
  • - + Experience
  • diff --git a/src/components/LinkButton.astro b/src/components/LinkButton.astro index 98e396a..daca4cb 100644 --- a/src/components/LinkButton.astro +++ b/src/components/LinkButton.astro @@ -8,7 +8,14 @@ export interface Props { newTarget?: boolean; } -const { href, className, ariaLabel, title, disabled = false, newTarget = true } = Astro.props; +const { + href, + className, + ariaLabel, + title, + disabled = false, + newTarget = true, +} = Astro.props; --- diff --git a/src/content/blog/backup-mysql-databases-in-kubernetes.md b/src/content/blog/backup-mysql-databases-in-kubernetes.md index 090f530..ed8ded0 100644 --- a/src/content/blog/backup-mysql-databases-in-kubernetes.md +++ b/src/content/blog/backup-mysql-databases-in-kubernetes.md @@ -12,8 +12,7 @@ tags: - bash - backup ogImage: "" -description: - In this post, we will show you how to create a MySQL server backup using Kubernetes CronJobs. +description: In this post, we will show you how to create a MySQL server backup using Kubernetes CronJobs. --- In this post, we will show you how to create a MySQL server backup using Kubernetes CronJobs. @@ -22,13 +21,14 @@ In our case, we do not have a managed MySQL server. But we want to backup it to For this we first build a container that can execute our tasks, because we will certainly need several tasks to backup our cluster. ## CronJob Agent Container + First, we'll show you our Dockerfile so you know what we need. ```Dockerfile FROM alpine:3.10 # Update -RUN apk --update add --no-cache bash nodejs-current yarn curl busybox-extras vim rsync git mysql-client openssh-client +RUN apk --update add --no-cache bash nodejs-current yarn curl busybox-extras vim rsync git mysql-client openssh-client RUN curl -LO https://storage.googleapis.com/kubernetes-release/release/v1.18.0/bin/linux/amd64/kubectl && chmod +x ./kubectl && mv ./kubectl /usr/local/bin/kubectl # Scripts @@ -41,6 +41,7 @@ RUN mkdir /var/backup/mysql ``` ## Backup Script + And now our backup script which the container executes. Our script is quite simple, we get all tables with the mysql client, export them as sql file, pack them in a zip file and send them in a 8 hours interval to our NAS. @@ -89,6 +90,7 @@ rsync -avz $BACKUPDIR/backup-${NOW}.tar.gz root@$BACKUPSERVER:$BACKUPREMOTEDIR ``` ## Kubernetes CronJob Deployment + Finally we show you the kubernetes deployment for our agent. In the deployment, our agent is defined as a CronJob that runs every 8 hours. @@ -111,7 +113,7 @@ spec: containers: - name: cronjob-agent image: xxx/cronjob-agent - command: ["bash", "/srv/jobs/backup-mariadb.sh"] + command: ["bash", "/srv/jobs/backup-mariadb.sh"] volumeMounts: - mountPath: /root/.ssh/id_rsa.pub name: cronjob-default-config @@ -129,4 +131,4 @@ spec: name: cronjob-default-config defaultMode: 256 restartPolicy: Never -``` \ No newline at end of file +``` diff --git a/src/content/blog/baremetal-cni-setup-with-cilium.md b/src/content/blog/baremetal-cni-setup-with-cilium.md index f0eb909..5a8a943 100644 --- a/src/content/blog/baremetal-cni-setup-with-cilium.md +++ b/src/content/blog/baremetal-cni-setup-with-cilium.md @@ -10,13 +10,13 @@ tags: - cni - baremetal ogImage: "" -description: - In a freshly set up Kubernetes cluster, we need a so-called CNI. This CNI is not always present after installation. +description: In a freshly set up Kubernetes cluster, we need a so-called CNI. This CNI is not always present after installation. --- In a freshly set up Kubernetes cluster, we need a so-called CNI. This CNI is not always present after installation. ## What is a Container Network Interface (CNI)? + CNI is a network framework that allows the dynamic configuration of networking resources through a group of Go-written specifications and libraries. The specification mentioned for the plugin outlines an interface that would configure the network, provisioning the IP addresses, and mantain multi-host connectivity. In the Kubernetes context, the CNI seamlessly integrates with the kubelet to allow automatic network configuration between pods using an underlay or overlay network. An underlay network is defined at the physical level of the networking layer composed of routers and switches. In contrast, the overlay network uses a virtual interface like VxLAN to encapsulate the network traffic. @@ -26,6 +26,7 @@ Once the network configuration type is specified, the runtime defines a network In addition to Kubernetes networking, CNI also supports Kubernetes-based platforms like OpenShift to provide a unified container communication across the cluster through software-defined networking (SDN) approach. ### What is Cilium? + Cilium is an open-source, highly scalable Kubernetes CNI solution developed by Linux kernel developers. Cilium secures network connectivity between Kubernetes services by adding high-level application rules utilizing eBPF filtering technology. Cilium is deployed as a daemon `cilium-agent` on each node of the Kubernetes cluster to manage operations and translates the network definitions to eBPF programs. The communication between pods happens over an overlay network or utilizing a routing protocol. Both IPv4 and IPv6 addresses are supported for cases. Overlay network implementation utilizes VXLAN tunneling for packet encapsulation while native routing happens through unencapsulated BGP protocol. @@ -37,10 +38,12 @@ Its network and application layer awareness manages packet inspection, and the a Cilium also has support for Kubernetes Network Policies through HTTP request filters. The policy configuration can be written into a YAML or JSON file and offers both ingress and egress enforcements. Admins can accept or reject requests based on the request method or path header while integrating policies with service mesh like Istio. ### Preparation + For the installation we need the CLI from Cilium. We can install this with the following commands: **Mac OSx** + ```bash curl -L --remote-name-all https://github.com/cilium/cilium-cli/releases/latest/download/cilium-darwin-amd64.tar.gz{,.sha256sum} shasum -a 256 -c cilium-darwin-amd64.tar.gz.sha256sum @@ -49,6 +52,7 @@ rm cilium-darwin-amd64.tar.gz{,.sha256sum} ``` **Linux** + ```bash curl -L --remote-name-all https://github.com/cilium/cilium-cli/releases/latest/download/cilium-linux-amd64.tar.gz{,.sha256sum} sha256sum --check cilium-linux-amd64.tar.gz.sha256sum @@ -57,14 +61,18 @@ rm cilium-linux-amd64.tar.gz{,.sha256sum} ``` ### Install Cilium + You can install Cilium on any Kubernetes cluster. These are the generic instructions on how to install Cilium into any Kubernetes cluster. The installer will attempt to automatically pick the best configuration options for you. #### Requirements + - Kubernetes must be configured to use CNI - Linux kernel >= 4.9.17 #### Install + Install Cilium into the Kubernetes cluster pointed to by your current kubectl context: + ```bash cilium install ``` @@ -72,7 +80,9 @@ cilium install If the installation fails for some reason, run `cilium status` to retrieve the overall status of the Cilium deployment and inspect the logs of whatever pods are failing to be deployed. ### Validate the Installation + To validate that Cilium has been properly installed, you can run + ```bash $ cilium status --wait /¯¯\ @@ -91,6 +101,7 @@ Image versions cilium quay.io/cilium/cilium:v1.9.5: 2 ``` Run the following command to validate that your cluster has proper network connectivity: + ```bash $ cilium connectivity test ℹ️ Monitor aggregation detected, will skip some flow validation steps @@ -101,4 +112,5 @@ $ cilium connectivity test --------------------------------------------------------------------------------------------------------------------- ✅ 69/69 tests successful (0 warnings) ``` -Congratulations! You have a fully functional Kubernetes cluster with Cilium. 🎉 \ No newline at end of file + +Congratulations! You have a fully functional Kubernetes cluster with Cilium. 🎉 diff --git a/src/content/blog/site-to-site-vpn-for-google-kubernetes-engine.md b/src/content/blog/site-to-site-vpn-for-google-kubernetes-engine.md index 8766703..ddef545 100644 --- a/src/content/blog/site-to-site-vpn-for-google-kubernetes-engine.md +++ b/src/content/blog/site-to-site-vpn-for-google-kubernetes-engine.md @@ -10,8 +10,7 @@ tags: - openvpn - google ogImage: "" -description: - In this tutorial I will try to explain you briefly and concisely how you can set up a site-to-site VPN for the Google Cloud Network. +description: In this tutorial I will try to explain you briefly and concisely how you can set up a site-to-site VPN for the Google Cloud Network. --- In this tutorial I will try to explain you briefly and concisely how you can set up a site-to-site VPN for the Google Cloud Network. @@ -23,13 +22,17 @@ We need 2 virtual machines. The first one on the side of our office and the othe #### Setup OpenVPN Clients ##### Site-to-Site Client Office Side + We need to install OpenVPN, we do it as follows: + ```bash apt install openvpn -y ``` + After that we add our OpenVPN configuration under this path `/etc/openvpn/s2s.conf`. -*s2s.conf* +_s2s.conf_ + ``` # Use a dynamic tun device. # For Linux 2.2 or non-Linux OSes, @@ -40,14 +43,14 @@ After that we add our OpenVPN configuration under this path `/etc/openvpn/s2s.co dev tun # Our OpenVPN peer is the Google gateway. -remote IP_GOOGLE_VPN_CLIENT +remote IP_GOOGLE_VPN_CLIENT ifconfig 4.1.0.2 4.1.0.1 route 10.156.0.0 255.255.240.0 # Google Cloud VM Network route 10.24.0.0 255.252.0.0 # Google Kubernetes Pod Network -push "route 192.168.10.0 255.255.255.0" # Office Network +push "route 192.168.10.0 255.255.255.0" # Office Network # Our pre-shared static key #secret static.key @@ -78,11 +81,15 @@ verb 3 log /etc/openvpn/s2s.log ``` + We also have to enable the IPv4 forward function in the kernel, so we go to `/etc/sysctl.conf` and comment out the following line: + ``` net.ipv4.ip_forward=1 ``` + We can then start our OpenVPN client with this command: + ```bash systemctl start openvpn@s2s ``` @@ -90,11 +97,13 @@ systemctl start openvpn@s2s On the Office side we have to open the port for the OpenVPN client that the other side can connect. ##### Site-to-Site Client Google Side + When setting up the OpenVPN client on Google's site, we need to consider the following settings when creating it. When we create the machine, we need to enable this option in the network settings: ![Google Cloud Network Settings](https://i.imgur.com/OXEkhxo.png) Also on this side we have to install the OpenVPN client again and then add this config under the path `/etc/openvpn/s2s.conf`: + ``` # Use a dynamic tun device. # For Linux 2.2 or non-Linux OSes, @@ -105,7 +114,7 @@ Also on this side we have to install the OpenVPN client again and then add this dev tun # Our OpenVPN peer is the Office gateway. -remote IP_OFFICE_VPN_CLIENT +remote IP_OFFICE_VPN_CLIENT ifconfig 4.1.0.2 4.1.0.1 @@ -143,12 +152,15 @@ verb 3 log /etc/openvpn/s2s.log ``` + We also have to enable the IPv4 forward function in the kernel, so we go to `/etc/sysctl.conf` and comment out the following line: + ``` net.ipv4.ip_forward=1 ``` ##### Connection test + Now that both clients are basically configured we can test the connection. Both clients have to be started with systemctl. After that we look at the logs with `tail -f /etc/openvpn/s2s-log` and wait for this message: ``` @@ -167,6 +179,7 @@ Wed May 5 08:28:12 2021 Initialization Sequence Completed If we can't establish a connection, we need to check if the ports are opened on both sides. #### Routing Google Cloud Network + After our clients have finished installing and configuring, we need to set the routes on Google. I will not map the Office side, as this is always different. But you have to route the networks for the Google network there as well. To set the route on Google we go to the network settings and then to Routes. Here you have to specify your office network so that the clients in the Google network know what to do. @@ -174,6 +187,7 @@ To set the route on Google we go to the network settings and then to Routes. Her ![Google Cloud Network Route](https://i.imgur.com/6Q2Drf4.png) #### IP-Masquerade-Agent + IP masquerading is a form of network address translation (NAT) used to perform many-to-one IP address translations, which allows multiple clients to access a destination using a single IP address. A GKE cluster uses IP masquerading so that destinations outside of the cluster only receive packets from node IP addresses instead of Pod IP addresses. This is useful in environments that expect to only receive packets from node IP addresses. You have to edit the ip-masq-agent and this configuration is responsible for letting the pods inside the nodes, reach other parts of the GCP VPC Network, more specifically the VPN. So, it allows pods to communicate with the devices that are accessible through the VPN. @@ -182,11 +196,12 @@ First of all we're gonna be working inside the kube-system namespace, and we're ```yaml nonMasqueradeCIDRs: - - 10.24.0.0/14 # The IPv4 CIDR the cluster is using for Pods (required) + - 10.24.0.0/14 # The IPv4 CIDR the cluster is using for Pods (required) - 10.156.0.0/20 # The IPv4 CIDR of the subnetwork the cluster is using for Nodes (optional, works without but I guess its better with it) masqLinkLocal: false resyncInterval: 60s ``` + and run `kubectl create configmap ip-masq-agent --from-file config --namespace kube-system` afterwards, configure the ip-masq-agent, put this in a `ip-masq-agent.yml` file: @@ -205,17 +220,17 @@ spec: spec: hostNetwork: true containers: - - name: ip-masq-agent - image: gcr.io/google-containers/ip-masq-agent-amd64:v2.4.1 - args: + - name: ip-masq-agent + image: gcr.io/google-containers/ip-masq-agent-amd64:v2.4.1 + args: - --masq-chain=IP-MASQ # To non-masquerade reserved IP ranges by default, uncomment the line below. # - --nomasq-all-reserved-ranges - securityContext: - privileged: true - volumeMounts: - - name: config - mountPath: /etc/config + securityContext: + privileged: true + volumeMounts: + - name: config + mountPath: /etc/config volumes: - name: config configMap: @@ -227,14 +242,14 @@ spec: - key: config path: ip-masq-agent tolerations: - - effect: NoSchedule - operator: Exists - - effect: NoExecute - operator: Exists - - key: "CriticalAddonsOnly" - operator: "Exists" + - effect: NoSchedule + operator: Exists + - effect: NoExecute + operator: Exists + - key: "CriticalAddonsOnly" + operator: "Exists" ``` and run `kubectl -n kube-system apply -f ip-masq-agent.yml`. -Now our site-to-site VPN should be set up. You should now test if you can ping the pods and if all other services work as you expect them to. \ No newline at end of file +Now our site-to-site VPN should be set up. You should now test if you can ping the pods and if all other services work as you expect them to. diff --git a/src/content/blog/why-docker-isnt-always-a-good-idea.md b/src/content/blog/why-docker-isnt-always-a-good-idea.md index d1dd0fc..69c6f74 100644 --- a/src/content/blog/why-docker-isnt-always-a-good-idea.md +++ b/src/content/blog/why-docker-isnt-always-a-good-idea.md @@ -10,9 +10,8 @@ tags: - network - haproxy ogImage: "" -description: - To briefly explain the situation. - We have a **HAProxy** running on a Debian server as a Docker container. This is the entrance node to a **Docker Swarm** cluster. +description: To briefly explain the situation. + We have a **HAProxy** running on a Debian server as a Docker container. This is the entrance node to a **Docker Swarm** cluster. --- To briefly explain the situation: @@ -40,4 +39,4 @@ With this setup, we get overhead into the system that we don't need. We have an If we use a lot of micro services it is important that we use something like Docker, because then we can share the kernel and it makes the deployment much easier. -But if we have only one application that is very important, it is better to keep it simple. \ No newline at end of file +But if we have only one application that is very important, it is better to keep it simple. diff --git a/src/content/blog/writing-backup-scripts-with-borg.md b/src/content/blog/writing-backup-scripts-with-borg.md index fe94672..adcfb2c 100644 --- a/src/content/blog/writing-backup-scripts-with-borg.md +++ b/src/content/blog/writing-backup-scripts-with-borg.md @@ -10,8 +10,7 @@ tags: - linux - backup ogImage: "" -description: - Since we all know that the first rule is "no backup, no pity", I'll show you how you can use Borg to back up your important data in an encrypted way with relative ease. +description: Since we all know that the first rule is "no backup, no pity", I'll show you how you can use Borg to back up your important data in an encrypted way with relative ease. --- Since we all know that the first rule is "no backup, no pity", I'll show you how you can use Borg to back up your important data in an encrypted way with relative ease. @@ -19,14 +18,17 @@ Since we all know that the first rule is "no backup, no pity", I'll show you how If you do not want to use a second computer, but an external hard drive, you can adjust this later in the script and ignore the points in the instructions for the second computer. ### Requirements - - 2 Linux Computers - - Borg - - SSH - - Storage - - More than 5 brain cells + +- 2 Linux Computers +- Borg +- SSH +- Storage +- More than 5 brain cells ### Installation + First we need to install borg on both computers so that we can back up on one and save on the other. + ```bash sudo apt install borgbackup ``` @@ -34,11 +36,13 @@ sudo apt install borgbackup Then we create a Borg repository. We can either use an external target or a local path. **External Target:** + ```bash borg init --encryption=repokey ssh://user@192.168.2.42:22/mnt/backup/borg ``` **Local Path:** + ```bash borg init --encryption=repokey /path/to/backup_folder ``` @@ -49,6 +53,7 @@ This way you don't have to enter a password and is simply nicer from my point of Once you have created everything and prepared the script with your parameters, I recommend that you run the script as a CronJob so that you no longer have to remember to back up your things yourself. **crontab example:** + ```bash #Minute Hour Day Month Day(Week) command #(0-59) (0-23) (1-31) (1-12) (1-7;1=Mo) @@ -56,6 +61,7 @@ Once you have created everything and prepared the script with your parameters, I ``` ### Automated script + ```bash #!/bin/sh @@ -113,6 +119,7 @@ exit ${global_exit} ``` ### Get your data from the backup + First, we create a temporary directory in which we can mount the backup. ```bash @@ -125,7 +132,9 @@ At this point you must remember that you can use an external destination or a lo ```bash borg mount ssh://user@192.168.2.42/mnt/backup/borg /tmp/borg-backup ``` + Once our repo is mounted, we can change into the directory and restore files via **rsync** or **cp**. ### Conclusion -I hope you could understand everything and now secure your shit sensibly. Because without a backup we are all lost! \ No newline at end of file + +I hope you could understand everything and now secure your shit sensibly. Because without a backup we are all lost! diff --git a/src/layouts/PostDetails.astro b/src/layouts/PostDetails.astro index 908122c..8971355 100644 --- a/src/layouts/PostDetails.astro +++ b/src/layouts/PostDetails.astro @@ -13,7 +13,8 @@ export interface Props { const { post } = Astro.props; -const { title, author, description, ogImage, canonicalURL, pubDatetime, tags } = post.data; +const { title, author, description, ogImage, canonicalURL, pubDatetime, tags } = + post.data; const { Content } = await post.render(); @@ -21,7 +22,13 @@ const ogUrl = new URL(ogImage ? ogImage : `${title}.png`, Astro.url.origin) .href; --- - +