<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Abdul Khaliq</title>
    <description>The latest articles on DEV Community by Abdul Khaliq (@kha7iq).</description>
    <link>https://dev.to/kha7iq</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F517973%2Ff513c463-35f3-48ee-86a8-597860b5619c.jpg</url>
      <title>DEV Community: Abdul Khaliq</title>
      <link>https://dev.to/kha7iq</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kha7iq"/>
    <language>en</language>
    <item>
      <title>Effortless NFS file transfer in CI/CD pipelines without Privileged access</title>
      <dc:creator>Abdul Khaliq</dc:creator>
      <pubDate>Mon, 22 May 2023 15:23:59 +0000</pubDate>
      <link>https://dev.to/kha7iq/effortless-nfs-file-transfer-in-cicd-pipelines-without-privileged-access-p1e</link>
      <guid>https://dev.to/kha7iq/effortless-nfs-file-transfer-in-cicd-pipelines-without-privileged-access-p1e</guid>
      <description>&lt;p&gt;In the realm of continuous integration and deployment (CI/CD) pipelines, the seamless transfer of artifacts to any remote servers holds immense significance.&lt;br&gt;
Traditionally, in the case of NFS, achieving this demands mounting of the nfs share inside the runner, thereby restricting it to a specific node and granting privileged access.&lt;br&gt;
However, NCP (NFS Copy), can be utilized to &lt;br&gt;
allows direct artifact copying to remote NFS servers without the need for mounting, eliminating the constraints of privileged access.&lt;/p&gt;

&lt;p&gt;In this article, we delve into the utilization of NCP in GitLab pipelines.&lt;/p&gt;
&lt;h2&gt;
  
  
  Understanding the Pipeline
&lt;/h2&gt;

&lt;p&gt;Let's examine a sample pipeline to better understand how NCP can be leveraged for artifact transfer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;stages&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;build&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;publish&lt;/span&gt;

&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;build&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;echo "build test artifact" &amp;gt; output.txt&lt;/span&gt;
  &lt;span class="na"&gt;artifacts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;output.txt&lt;/span&gt;
    &lt;span class="na"&gt;expire_in&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;2 hours&lt;/span&gt;

&lt;span class="na"&gt;publish&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;publish&lt;/span&gt;
  &lt;span class="na"&gt;needs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;build"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker.io/khaliq/ncp:latest&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;ncp to --host 192.168.0.80 --nfspath data --input output.txt&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The pipeline consists of two stages: &lt;code&gt;build&lt;/code&gt; and &lt;code&gt;publish&lt;/code&gt;. In the &lt;code&gt;build&lt;/code&gt; stage, a test artifact is created by echoing the text "build test artifact" into a file called &lt;code&gt;output.txt&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This stage is responsible for building the artifact that will later be transferred to the remote NFS server.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;publish&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;publish&lt;/span&gt;
  &lt;span class="na"&gt;needs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;build"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker.io/khaliq/ncp:ncp&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;ncp to --host 192.168.0.80 --nfspath data --input output.txt&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The publish stage is where the artifact is transferred using NCP. Here's a breakdown of the command used:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ncp to&lt;/code&gt;: Specifies the direction of the transfer, indicating that the artifact will be sent to the remote server.&lt;br&gt;
&lt;code&gt;--host&lt;/code&gt;: Specifies the IP address or hostname of the remote NFS server.&lt;br&gt;
&lt;code&gt;--nfspath&lt;/code&gt;: Defines the target path on the remote server where the artifact will be stored.&lt;br&gt;
&lt;code&gt;--input&lt;/code&gt;: Specifies the input artifact to be transferred, in this case, &lt;code&gt;output.txt&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;With this simple command, it handles the transfer of the artifact to the specified remote NFS server, without the need to mount nfs shares.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;NCP simplifies remote NFS server integration in CI/CD pipelines. By eliminating nfs share mounting and the need for privileged access, it streamlines artifact transfer, granting the freedom to run jobs anywhere.&lt;/p&gt;

&lt;p&gt;Checkout the &lt;a href="https://github.com/kha7iq/ncp"&gt;GitHub repository&lt;/a&gt; for more information.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Installing gitlab on kubernetes with kustomize</title>
      <dc:creator>Abdul Khaliq</dc:creator>
      <pubDate>Fri, 16 Jul 2021 08:14:04 +0000</pubDate>
      <link>https://dev.to/kha7iq/installing-gitlab-on-kubernetes-with-kustomize-3ee6</link>
      <guid>https://dev.to/kha7iq/installing-gitlab-on-kubernetes-with-kustomize-3ee6</guid>
      <description>&lt;h3&gt;
  
  
  Introduction
&lt;/h3&gt;

&lt;p&gt;In this article, I will describe all the steps required to setup GitLab CI/CD in kuberntes using kustomize.&lt;br&gt;
We will go through how to run GitLab on Kubernetes when you have related resources &lt;code&gt;postgres&lt;/code&gt;, &lt;code&gt;redis&lt;/code&gt;, &lt;code&gt;minio&lt;/code&gt;, &lt;code&gt;tls certificates&lt;/code&gt; etc already available in your setup.&lt;/p&gt;

&lt;p&gt;This is a very common scenario in companies and also for self-hosting that you already have these services in your environment and prefer to use the same for gitlab.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The all in one production installation may be easily performed with Helm. You can refer to official documentation from gitlab if that is your requirement.&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Requirements
&lt;/h3&gt;

&lt;p&gt;You will need the following in order to run gitlab.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Database : Postgres database is required for gitlab.&lt;/li&gt;
&lt;li&gt;Cache :   Redis is used for caching.&lt;/li&gt;
&lt;li&gt;Storage : Minio is used as object storage for &lt;code&gt;container registry&lt;/code&gt;, &lt;code&gt;gitlab backups&lt;/code&gt;, &lt;code&gt;terraform storage backend&lt;/code&gt;, &lt;code&gt;gitlab artifacts&lt;/code&gt; etc.&lt;/li&gt;
&lt;li&gt;Ingress Controller : Nginx ingress is part of installation.&lt;/li&gt;
&lt;li&gt;Persistent Volume : Gitaly will store &lt;code&gt;repository data&lt;/code&gt; data on disk, for that your kubernetes cluster must have a way of provisioning storage. You can install &lt;a href="https://github.com/rancher/local-path-provisioner"&gt;local path provisioner&lt;/a&gt; in your cluster for dynamically provisioning volumes.&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Repositories

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://github.com/kha7iq/gitlab-k8s"&gt;Gitlab Manifests&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/kha7iq/subvars"&gt;SubVars App&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Info: You can swap minio with any other object storage i.e S3 by changing connection info secret&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Lets get Started
&lt;/h2&gt;

&lt;p&gt;When installing gitlab with helm it generates the configmaps after rendering the templates with parameters, we can manually change these values in configmaps but its a hassle and not convenient.&lt;/p&gt;

&lt;p&gt;To make this process easy we will use a tool called &lt;a href="https://github.com/kha7iq/subvars"&gt;subvars&lt;/a&gt; which will let us render values defined as go templates from command line. Install it by following the instructions on &lt;a href="https://github.com/kha7iq/subvars"&gt;github&lt;/a&gt; page, we will use it later.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Download the release with manifests from &lt;a href="https://github.com/kha7iq/gitlab-k8s"&gt;github&lt;/a&gt; alternatively you can clone the repo, if you are cloning the repo remove the &lt;code&gt;.git&lt;/code&gt; folder afterwards as it creates issues some times when rendering multiple version of the same file with subvars.
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;RELEASE_VER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1.0
wget &lt;span class="nt"&gt;-q&lt;/span&gt; https://github.com/kha7iq/gitlab-k8s/archive/refs/tags/v&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;RELEASE_VER&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;.tar.gz
&lt;span class="nb"&gt;tar&lt;/span&gt; &lt;span class="nt"&gt;-xf&lt;/span&gt; v&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;RELEASE_VER&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;.tar.gz
&lt;span class="nb"&gt;cd &lt;/span&gt;gitlab-k8s-&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;RELEASE_VER&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;Lets start by setting the url for gitlab in our &lt;a href="https://github.com/kha7iq/gitlab-k8s/blob/master/ingress-nginx/kustomization.yaml"&gt;kustomization file&lt;/a&gt; within ingress-nginx folder. You will find two blocks, one for web-ui and second for registry along with tls-secret-name for https.
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;patch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|-&lt;/span&gt;
    &lt;span class="s"&gt;- op: replace&lt;/span&gt;
      &lt;span class="s"&gt;path: /spec/rules/0/host&lt;/span&gt;
      &lt;span class="s"&gt;value: your-gitlab-url.example.com&lt;/span&gt;
    &lt;span class="s"&gt;- op: replace&lt;/span&gt;
      &lt;span class="s"&gt;path: /spec/tls/0/hosts/0&lt;/span&gt;
      &lt;span class="s"&gt;value: your-gitlab-url.example.com&lt;/span&gt;
    &lt;span class="s"&gt;- op: replace&lt;/span&gt;
      &lt;span class="s"&gt;path: /spec/tls/0/secretName&lt;/span&gt;
      &lt;span class="s"&gt;value: example-com-wildcard-secret&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;We can create &lt;code&gt;minio-conn-secret&lt;/code&gt; containing configuration for minio. It will be used for all the enabled S3 buckets except gitlab backups, we will create that separately. Input the information as per your setup and create the kubernetes secret.&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;minio.config
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt; &amp;gt; minio.config
provider: AWS
region: us-east-1
aws_access_key_id: 4wsd6c468c0974006d
aws_secret_access_key: 5d5e6c468c0974006cdb41bc4ac2ba0d
aws_signature_version: 4
host: minio.example.com
endpoint: "https://minio.example.com"
path_style: true
&lt;/span&gt;&lt;span class="no"&gt;EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;Kubernetes secret
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl create secret generic minio-conn-secret &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--from-file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;connection&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;minio.config &lt;span class="nt"&gt;--dry-run&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;client &lt;span class="nt"&gt;-o&lt;/span&gt; yaml &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;minio-connection-secret.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;Next step is to create a secret with mino configuration for gitlab backup storage. Just replace minio endpoint, bucket name, access key &amp;amp; secret key.
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt; &amp;gt; storage.config
[default]
access_key = be59435b326e8b0eaa
secret_key = 6e0a10bd2253910e1657a21fd1690088
bucket_location = us-east-1
host_base = https://minio.example.com
host_bucket = https://minio.example.com/gitlab-backups
use_https = True
default_mime_type = binary/octet-stream
enable_multipart = True
multipart_max_chunks = 10000
multipart_chunk_size_mb = 128
recursive = True
recv_chunk = 65536
send_chunk = 65536
server_side_encryption = False
signature_v2 = True
socket_timeout = 300
use_mime_magic = False
verbosity = WARNING
website_endpoint = https://minio.example.com
&lt;/span&gt;&lt;span class="no"&gt;EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl create secret generic storage-config &lt;span class="nt"&gt;--from-file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;config&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;storage.config &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--dry-run&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;client &lt;span class="nt"&gt;-o&lt;/span&gt; yaml &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; secrets/storage-config.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;blockquote&gt;
&lt;p&gt;All other secrets can be used as is from repository or you can change all of them following &lt;a href="https://docs.gitlab.com/charts/installation/secrets.html"&gt;gitlab documentation&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;One of the most important secret is &lt;code&gt;gitlab-rails-secret&lt;/code&gt;, in case of a disaster where you have to restore gitlab from a backup you must apply the same secret in your cluster as these keys will be used to decrypt the database etc from backup. Make sure you keep this consistent after first install.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We reached the last part, Its alot of work to change database and other parameters one by one in configmaps.&lt;br&gt;
I have implemented some templating for this we can provide all the values via environment variables and render the manifests with subvars, it will output these to destination folder and replace all the parameters defined as go templates.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Variables are self explanatory, &lt;code&gt;GITLAB_GITALY_STORAGE_SIZE&lt;/code&gt; variable is used to specify how much storage is needed for gitaly and &lt;code&gt;GITLAB_STORAGE_CLASS&lt;/code&gt; is the name of storage class.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;GITLAB_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;gitlab.example.com &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nv"&gt;GITLAB_REGISTRY_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;registry.example.com &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nv"&gt;GITLAB_PAGES_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;pages.example.com &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nv"&gt;GITLAB_POSTGRES_HOST&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;192.168.1.90 &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nv"&gt;GITLAB_POSTGRES_PORT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;5432 &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nv"&gt;GITLAB_POSTGRES_USER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;gitlab &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nv"&gt;GITLAB_POSTGRES_DB_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;gitlabhq_production &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nv"&gt;GITLAB_REDIS_HOST&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;192.168.1.91:6379 &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nv"&gt;GITLAB_GITALY_STORAGE_SIZE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;15Gi &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nv"&gt;GITLAB_STORAGE_CLASS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;local-path &lt;span class="se"&gt;\&lt;/span&gt;
subvars &lt;span class="nb"&gt;dir&lt;/span&gt; &lt;span class="nt"&gt;--input&lt;/span&gt; gitlab-k8s-1.0 &lt;span class="nt"&gt;--out&lt;/span&gt; dirName
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Change into &lt;code&gt;dirName/gitlab-k8s-1.0&lt;/code&gt; you can have a look to confirm if everything is in order before applying this in cluster.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The final step is to create the namespace &lt;code&gt;gitlab&lt;/code&gt; and build with kustomize or kubectl. I prefer kustomize but you can also use kubectl with &lt;code&gt;-k&lt;/code&gt; flag.&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Create namespace
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl create namespace gitlab
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Apply the final manifest
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kustomize build gitlab-k8s-1.0/ | kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; -
&lt;span class="c"&gt;# or following if you have already changed into directory&lt;/span&gt;
kustomize build &lt;span class="nb"&gt;.&lt;/span&gt; | kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; -

&lt;span class="c"&gt;# With kubectl&lt;/span&gt;
kubectl apply &lt;span class="nt"&gt;-k&lt;/span&gt;  gitlab-k8s-1.0/
&lt;span class="c"&gt;# or following if you have already changed into directory&lt;/span&gt;
kubectl apply &lt;span class="nt"&gt;-k&lt;/span&gt;  &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Head over to the endpoint you have configured for gitlab &lt;code&gt;https://gitlab.example.com&lt;/code&gt; and login.&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Info: 
Default passwords

&lt;ul&gt;
&lt;li&gt;Gitlab 'root' user's password
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   LAwGTzCebner4Kvd23UMGEOFoGAgEHYDszrsSPfAp6lCW15S4fbvrVrubWsua9PI
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Postgres password configured as secret
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;    ZDVhZDgxNWY2NmMzODAwMTliYjdkYjQxNWEwY2UwZGMK
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>tutorial</category>
      <category>devops</category>
      <category>kubernetes</category>
      <category>gitlab</category>
    </item>
    <item>
      <title>Performing code checks with GitHub actions &amp; sending results to slack</title>
      <dc:creator>Abdul Khaliq</dc:creator>
      <pubDate>Thu, 29 Apr 2021 19:15:55 +0000</pubDate>
      <link>https://dev.to/kha7iq/performing-code-checks-with-github-actions-sending-results-to-slack-m6l</link>
      <guid>https://dev.to/kha7iq/performing-code-checks-with-github-actions-sending-results-to-slack-m6l</guid>
      <description>&lt;h3&gt;
  
  
  What is a GitHub Action ?
&lt;/h3&gt;

&lt;p&gt;A GitHub action is an element of your custom workflow that is triggered when a push or pull request is created and performs some action such as checking code, sending a message or deploying the application.&lt;/p&gt;

&lt;p&gt;The most important concept of GitHub actions is their composability. You can assemble actions as building blocks and build a workflow that matches your needs.&lt;/p&gt;

&lt;p&gt;In this article we would like to explore how we can put certain actions together and perform different steps based on outcome.&lt;/p&gt;

&lt;h4&gt;
  
  
  Lets create an action which performs linting checks on a new pull request.
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pull_request&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;lint-code&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Perform Checks&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v2&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;golangci-lint&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;golangci/golangci-lint-action@v2&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1.29&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h4&gt;
  
  
  Sending alerts
&lt;/h4&gt;

&lt;p&gt;Next we want to get a notification on slack if these checks passed or failed.&lt;/p&gt;

&lt;p&gt;We will use &lt;a href="https://github.com/kha7iq/pingme-action" rel="noopener noreferrer"&gt;PingMe Action&lt;/a&gt; to send these alerts.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pull_request&lt;/span&gt;

&lt;span class="c1"&gt;# Get values from github secrets of slack token and target  channels and set the variables.&lt;/span&gt;
&lt;span class="c1"&gt;# we can set these within the action block as well for pass/fail.&lt;/span&gt;
&lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;SLACK_TOKEN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.SLACK_TOKEN }}&lt;/span&gt;
  &lt;span class="na"&gt;SLACK_CHANNELS&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.SLACK_CHANNELS }}&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;lint-code&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubunut-latest&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Perform Checks&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v2&lt;/span&gt;
      &lt;span class="c1"&gt;# We want to perform checks and see if the code is properly linted.&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;golangci-lint&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;golangci/golangci-lint-action@v2&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1.29&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Alert when checks fail&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;kha7iq/pingme-action@v1&lt;/span&gt;
        &lt;span class="c1"&gt;# This action will only run if checks failed.&lt;/span&gt;
        &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;failure()&lt;/span&gt;
        &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;SLACK_MSG_TITLE&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;🟢&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;New&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Request:&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;${{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;github.ref&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}'&lt;/span&gt;
          &lt;span class="na"&gt;SLACK_MESSAGE&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Event&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;is&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;triggerd&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;by&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;${{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;github.event_name&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Checks&lt;/span&gt;&lt;span class="nv"&gt;  &lt;/span&gt;&lt;span class="s"&gt;❌&lt;/span&gt;&lt;span class="nv"&gt;  &lt;/span&gt;&lt;span class="s"&gt;${{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;job.status&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}'&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;slack&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Alert when checks pass&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;kha7iq/pingme-action@v1&lt;/span&gt;
        &lt;span class="c1"&gt;# This action will only run if checks are successfull.&lt;/span&gt;
        &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;success()&lt;/span&gt;
        &lt;span class="c1"&gt;# Message and Title are string values, you can create custome message or title.&lt;/span&gt;
        &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;SLACK_MSG_TITLE&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;🟢&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;New&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Request:&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;${{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;github.ref&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}'&lt;/span&gt;
          &lt;span class="na"&gt;SLACK_MESSAGE&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Event&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;is&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;triggerd&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;by&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;${{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;github.event_name&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Checks&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;✅&lt;/span&gt;&lt;span class="nv"&gt;  &lt;/span&gt;&lt;span class="s"&gt;${{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;job.status&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}'&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;slack&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Passed&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdg83sebw7rlhv1zi59h3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdg83sebw7rlhv1zi59h3.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Failed&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6tm3ph2h1dsd66ivf431.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6tm3ph2h1dsd66ivf431.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;
  
  
  You can see this workflow in action here.
&lt;/h4&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/kha7iq" rel="noopener noreferrer"&gt;
        kha7iq
      &lt;/a&gt; / &lt;a href="https://github.com/kha7iq/pingme" rel="noopener noreferrer"&gt;
        pingme
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      PingMe is a CLI which provides the ability to send messages or alerts to multiple messaging platforms &amp;amp; email.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;
  &lt;br&gt;
  &lt;/h2&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer nofollow" href="https://raw.githubusercontent.com/kha7iq/pingme/master/.github/img/logo.png"&gt;&lt;img width="30%" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fkha7iq%2Fpingme%2Fmaster%2F.github%2Fimg%2Flogo.png"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;

&lt;div class="markdown-heading"&gt;
&lt;h4 class="heading-element"&gt;PingMe CLI&lt;/h4&gt;
&lt;/div&gt;

&lt;p&gt;
   &lt;a href="https://github.com/kha7iq/pingme/releases" rel="noopener noreferrer"&gt;
   &lt;img alt="Release" src="https://camo.githubusercontent.com/9a29dabe89b3083ef6cfc1f63c900fd9e8ba029f014f063dd2de66f7ff28710d/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f762f72656c656173652f6b68613769712f70696e676d65"&gt;
   &lt;/a&gt;&lt;a href="https://goreportcard.com/report/github.com/kha7iq/pingme" rel="nofollow noopener noreferrer"&gt;
   &lt;img alt="Go Report Card" src="https://camo.githubusercontent.com/900c7fe638e593914fe19134c3aa363c6578b861114d4beab037b80ffd533358/68747470733a2f2f676f7265706f7274636172642e636f6d2f62616467652f6769746875622e636f6d2f6b68613769712f70696e676d65"&gt;
   &lt;/a&gt;&lt;a href="https://github.com/kha7iq/pingme/issues" rel="noopener noreferrer"&gt;
   &lt;img alt="GitHub issues" src="https://camo.githubusercontent.com/02f23728f7ac5ada8278b6cb7aa8c58ace09e180f1de00c777b238d27c901cc8/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6973737565732f6b68613769712f70696e676d653f7374796c653d666c61742d737175617265266c6f676f3d676974687562266c6f676f436f6c6f723d7768697465"&gt;
   &lt;/a&gt;&lt;a href="https://github.com/kha7iq/pingme/blob/master/LICENSE.md" rel="noopener noreferrer"&gt;
   &lt;img alt="License" src="https://camo.githubusercontent.com/61edac238b1b0eff9a445dc78a86bd1238184aea4ebb561333466696abb8fe60/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f6b68613769712f70696e676d65"&gt;
   &lt;/a&gt;&lt;a href="https://github.com/agarrharr/awesome-cli-apps#devops" rel="noopener noreferrer"&gt;
   &lt;img alt="Awesome" src="https://camo.githubusercontent.com/8693bde04030b1670d5097703441005eba34240c32d1df1eb82a5f0d6716518e/68747470733a2f2f63646e2e7261776769742e636f6d2f73696e647265736f726875732f617765736f6d652f643733303566333864323966656437386661383536353265336136336531353464643865383832392f6d656469612f62616467652e737667"&gt;
   &lt;/a&gt;&lt;a href="https://pkg.go.dev/github.com/kha7iq/pingme" rel="nofollow noopener noreferrer"&gt;
   &lt;img alt="Go Dev Reference" src="https://camo.githubusercontent.com/2a61b8eea27626e6f50eaed19b8918a149f8356e845a4f8f875ff9172f39d1e2/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f676f2e6465762d7265666572656e63652d3030376439633f6c6f676f3d676f266c6f676f436f6c6f723d7768697465267374796c653d666c6174"&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;
  &lt;a href="https://kha7iq.github.io/pingme" rel="nofollow noopener noreferrer"&gt;Documentation&lt;/a&gt; •
  &lt;a href="https://github.com/kha7iq/pingme#supported-services" rel="noopener noreferrer"&gt;Supported Services&lt;/a&gt; •
  &lt;a href="https://github.com/kha7iq/pingme#install" rel="noopener noreferrer"&gt;Install&lt;/a&gt; •
  &lt;a href="https://github.com/kha7iq/pingme#github-action" rel="noopener noreferrer"&gt;Github Action&lt;/a&gt; •
  &lt;a href="https://github.com/kha7iq/pingme#configuration" rel="noopener noreferrer"&gt;Configuration&lt;/a&gt; •
  &lt;a href="https://github.com/kha7iq/pingme#contributing" rel="noopener noreferrer"&gt;Contributing&lt;/a&gt; •
&lt;/p&gt;




&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;About&lt;/h2&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;PingMe&lt;/strong&gt; is a personal project to satisfy my needs of having alerts, most
major platforms have integration to send alerts but its not always useful,
either you are stuck with one particular platform, or you have to do alot of
integrations. I needed a small utility which i can just call from my backup scripts,
cron jobs, CI/CD pipelines or from anywhere to send a message with particular
information. And i can ship it everywhere with ease. Hence, the birth of PingMe.&lt;/p&gt;
&lt;p&gt;Everything is configurable via environment variables, and you can simply export
the logs or messages to a variable which will be sent as message, and most of
all this serves as a swiss army knife sort of tool which supports multiple
platforms.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Supported services&lt;/h2&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Discord&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Email&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Gotify&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Line&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Mastodon&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Mattermost&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Microsoft&lt;/em&gt;…&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/kha7iq/pingme" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


</description>
      <category>github</category>
      <category>beginners</category>
      <category>tutorial</category>
      <category>go</category>
    </item>
    <item>
      <title>Send alerts to multiple platforms from your scripts</title>
      <dc:creator>Abdul Khaliq</dc:creator>
      <pubDate>Tue, 27 Apr 2021 10:32:37 +0000</pubDate>
      <link>https://dev.to/kha7iq/send-alerts-to-multiple-platforms-from-your-scripts-3clm</link>
      <guid>https://dev.to/kha7iq/send-alerts-to-multiple-platforms-from-your-scripts-3clm</guid>
      <description>&lt;p&gt;In this article, we will illustrate how to configure and send messages to multiple platforms from your scripts.&lt;/p&gt;

&lt;p&gt;A notification can be setup based on success or failure of a task or if you want to have an alert when a certain condition is meet.&lt;/p&gt;

&lt;p&gt;This article uses a small binary &lt;a href="https://github.com/kha7iq/pingme"&gt;PingMe&lt;/a&gt; to send this notification, you can find more information about it on github.&lt;/p&gt;

&lt;h4&gt;
  
  
  Lets dig right into it
&lt;/h4&gt;

&lt;p&gt;In this first example we would like to get a notification when any one logs into our server via ssh.&lt;br&gt;
Multiple options are available for messaging platform in this example we will use Pushover service.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Download &amp;amp; install&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;First step is to download install the binary itself on the system which we will use for sending notifications.&lt;br&gt;
We can download the binary from github and extract in the current folder.&lt;/p&gt;

&lt;p&gt;Its executable but for good measure we will make it executable and then move the binary in system path, in this case its &lt;code&gt;/usr/local/bin&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;App is also available as deb and rpm, for windows users a &lt;a href="https://github.com/kha7iq/pingme/releases"&gt;compatible binary&lt;/a&gt; is can be found under &lt;a href="https://github.com/kha7iq/pingme/releases"&gt;release&lt;/a&gt; page.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wget &lt;span class="nt"&gt;-q&lt;/span&gt; https://github.com/kha7iq/pingme/releases/download/v0.1.5/pingme_Linux_x86_64.tar.gz &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;tar&lt;/span&gt; &lt;span class="nt"&gt;-xf&lt;/span&gt; pingme_Linux_x86_64.tar.gz
&lt;span class="nb"&gt;chmod&lt;/span&gt; +x pingme
&lt;span class="nb"&gt;sudo mv &lt;/span&gt;pingme /usr/local/bin/pingme
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Lets create our script and configure notifications
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Send Alert when any user login via ssh&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;/etc/profile.d/&lt;/code&gt; is read at every login (for bash shell users). The &lt;code&gt;if&lt;/code&gt; statement will only return &lt;code&gt;true&lt;/code&gt; if the user has logged in via ssh, which in turn will cause the indented code block to be run.&lt;/p&gt;

&lt;p&gt;Create a file with desired name i.e &lt;code&gt;/etc/profile.d/login.sh&lt;/code&gt; and paste the following.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;pushover_token&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;your token here&amp;gt;"&lt;/span&gt;
&lt;span class="nv"&gt;pushover_user&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;your user here&amp;gt;"&lt;/span&gt;
&lt;span class="nv"&gt;alert_title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"Alert SSH Login: &lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$SSH_CLIENT&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nv"&gt;PUSHOVER_MESSAGE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"ssh login to &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;USER&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;@&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;hostname&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt; from &lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$SSH_CLIENT&lt;/span&gt;|awk &lt;span class="s1"&gt;'{print $1}'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    pingme pushover &lt;span class="nt"&gt;--msg&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$PUSHOVER_MESSAGE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;--token&lt;/span&gt; &lt;span class="nv"&gt;$pushover_token&lt;/span&gt; &lt;span class="nt"&gt;--user&lt;/span&gt; &lt;span class="nv"&gt;$pushover_user&lt;/span&gt; &lt;span class="nt"&gt;--title&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$alert_title&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Pushover Alert&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7jjnIdcv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lo2auqowinofy8c9qx4j.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7jjnIdcv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lo2auqowinofy8c9qx4j.jpg" alt="Pushover"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Send alert on failure or success of a cronjob
&lt;/h4&gt;

&lt;p&gt;We have a cronjob which runs and take backup of our files, we would like to know if this backup has been created successfully&lt;br&gt;
or failed. In this example we are going to send the alert to telegram channel.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cron Job
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; /home/user/scripts/backup.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Backup Script
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="c"&gt;# telegram bot token&lt;/span&gt;
&lt;span class="nv"&gt;token&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;token here&amp;gt;"&lt;/span&gt;
&lt;span class="c"&gt;# Telegram channel&lt;/span&gt;
&lt;span class="nv"&gt;channel&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;channel here&amp;gt;"&lt;/span&gt;
&lt;span class="nv"&gt;DATE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt; +%d-%m-%Y-%T&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;BACKUP_FILE_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"postgres_db-&lt;/span&gt;&lt;span class="nv"&gt;$DATE&lt;/span&gt;&lt;span class="s2"&gt;.tar.gz"&lt;/span&gt;
&lt;span class="nv"&gt;BACKUP_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/home/user/backup"&lt;/span&gt;

&lt;span class="nb"&gt;tar&lt;/span&gt; &lt;span class="nt"&gt;-zcpf&lt;/span&gt; &lt;span class="nv"&gt;$BACKUP_DIR&lt;/span&gt;/&lt;span class="nv"&gt;$BACKUP_FILE_NAME&lt;/span&gt; &lt;span class="nv"&gt;$HOME&lt;/span&gt;/dbfiles

&lt;span class="c"&gt;# check the exit code and send alert based on that.&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;$?&lt;/span&gt; &lt;span class="nt"&gt;-eq&lt;/span&gt; 0 &lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nv"&gt;title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"Success: Backup created successfully"&lt;/span&gt;
    /usr/local/bin/pingme telegram &lt;span class="nt"&gt;--msg&lt;/span&gt; &lt;span class="s2"&gt;"Successfully backed up &lt;/span&gt;&lt;span class="nv"&gt;$BACKUP_FILE_NAME&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-t&lt;/span&gt; &lt;span class="nv"&gt;$token&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="nv"&gt;$channel&lt;/span&gt; &lt;span class="nt"&gt;--title&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$title&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;else
    &lt;/span&gt;&lt;span class="nv"&gt;title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"Failed: Error creating backup"&lt;/span&gt;
    /usr/local/bin/pingme telegram &lt;span class="nt"&gt;--msg&lt;/span&gt; &lt;span class="s2"&gt;"Unsuccessful backup of &lt;/span&gt;&lt;span class="nv"&gt;$BACKUP_FILE_NAME&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-t&lt;/span&gt; &lt;span class="nv"&gt;$token&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="nv"&gt;$channel&lt;/span&gt; &lt;span class="nt"&gt;--title&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$title&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Telegram Alert&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--635eyLUb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qx6jq6dzc9vwb0chx5np.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--635eyLUb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qx6jq6dzc9vwb0chx5np.png" alt="alt text"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>bash</category>
      <category>slack</category>
      <category>telegram</category>
      <category>linux</category>
    </item>
  </channel>
</rss>
