<?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: Kehinde Alade</title>
    <description>The latest articles on DEV Community by Kehinde Alade (@kennibravo).</description>
    <link>https://dev.to/kennibravo</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%2F554081%2F49ff6c75-4670-4b87-9a99-24784f690435.jpg</url>
      <title>DEV Community: Kehinde Alade</title>
      <link>https://dev.to/kennibravo</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kennibravo"/>
    <language>en</language>
    <item>
      <title>Ansible Tutorial: Automate and Configure Remote Linux Servers</title>
      <dc:creator>Kehinde Alade</dc:creator>
      <pubDate>Tue, 25 Oct 2022 16:45:36 +0000</pubDate>
      <link>https://dev.to/kennibravo/ansible-tutorial-automate-and-configure-remote-linux-servers-3l9</link>
      <guid>https://dev.to/kennibravo/ansible-tutorial-automate-and-configure-remote-linux-servers-3l9</guid>
      <description>&lt;p&gt;What if you have to remotely automate Linux servers, maybe about 200? What options do you have? You could decide to use the following;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Shell&lt;/li&gt;
&lt;li&gt;Python&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you have sufficient experience in programming, you can write a Shell script or a Python script to do that for you; what if you don't know Shell or Python? You'd have to learn either one. In most cases, you may not want to go through such stress.&lt;br&gt;
In this tutorial, I will be explaining the process of automating using Ansible as you'd do to a beginner, but there are some requirements to follow;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Linux&lt;/li&gt;
&lt;li&gt;Vagrant (The first article in this series)&lt;/li&gt;
&lt;li&gt;YAML (You can learn at &lt;a href="https://docs.ansible.com/ansible/latest/reference_appendices/YAMLSyntax.html#yaml-syntax" rel="noopener noreferrer"&gt;Ansible YAML&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's just about all, let's dive right in 🎶 &lt;/p&gt;

&lt;p&gt;We have set up three Linux servers in Virtualbox using Vagrant; they all use the Ubuntu image.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Nodecontroller:&lt;/strong&gt; This is the controller server where we'll Install Ansible.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;target01:&lt;/strong&gt; As its name implies, this is the target server, we'd be automating this server and &lt;strong&gt;target02&lt;/strong&gt;. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's ssh into the &lt;code&gt;nodecontroller&lt;/code&gt; and Install Ansible, we'd be following the guide at &lt;a href="https://docs.ansible.com/ansible/latest/installation_guide/installation_distros.html" rel="noopener noreferrer"&gt;Ansible Installation Guide&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;CD into where you have your &lt;code&gt;Vagrantfile&lt;/code&gt;, run &lt;code&gt;vagrant status&lt;/code&gt; to verify the VMs we installed in the first article then;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;vagrant up &amp;amp;&amp;amp; vagrant ssh nodecontroller
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It starts up the VMs &lt;strong&gt;AND&lt;/strong&gt; ssh into the nodecontroller, now to install Ansible;&lt;/p&gt;

&lt;p&gt;Run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo apt install ansible
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If it can't find the package, go ahead and follow the instruction below, otherwise skip the adding the source list part;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;echo deb http://ppa.launchpad.net/ansible/ansible/ubuntu trusty main &amp;gt;&amp;gt; /etc/apt/sources.list
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It adds the ansible source to the sources list for Ubuntu if you see a &lt;code&gt;permission denied&lt;/code&gt; error even with using sudo;&lt;/p&gt;

&lt;p&gt;Run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;su
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then run the same command and &lt;code&gt;exit&lt;/code&gt; when done, next;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 93C4A3FD7BB9C367 
sudo apt update
sudo apt install ansible
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This should take a few minutes, after it's done, to verify it has been installed, run;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ansible --version
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see something like this, and then you're good to go;&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%2Fx4eeo5yo28fmzpkqyto5.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%2Fx4eeo5yo28fmzpkqyto5.png" alt="Ansible"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Getting started with Ansible
&lt;/h2&gt;

&lt;p&gt;Ansible has three main components, namely;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Control node:&lt;/strong&gt; This is our &lt;code&gt;nodecontroller.&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Managed node:&lt;/strong&gt; This is &lt;code&gt;target01&lt;/code&gt; and &lt;code&gt;target02&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inventory:&lt;/strong&gt; This is the list of our nodes organized on the control node, as it sounds, it stores the list of nodes we want to automate. &lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Let's create an Inventory
&lt;/h3&gt;

&lt;p&gt;Get the IP addresses of &lt;code&gt;target01&lt;/code&gt; and &lt;code&gt;target02&lt;/code&gt; by &lt;code&gt;vagrant ssh target01&lt;/code&gt; into them from your host(PC), then run &lt;code&gt;ifconfig&lt;/code&gt;, note them down and exit, and now SSH into your &lt;code&gt;nodecontroller.&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cat &amp;gt; inventory.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then paste;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;target01 ansible_host=192.168.56.4 ansible_ssh_pass=vagrant
target02 ansible_host=192.168.56.5 ansible_ssh_pass=vagrant
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Press Enter, then &lt;code&gt;Ctrl C&lt;/code&gt; to exit, then run &lt;code&gt;cat inventory.txt&lt;/code&gt; to verify the input. &lt;/p&gt;

&lt;p&gt;We added the &lt;code&gt;target01 and target02&lt;/code&gt; to the inventory file, the &lt;code&gt;target01 and target02&lt;/code&gt; are the name of the server, &lt;code&gt;ansible_host&lt;/code&gt; is a variable, and we stored each server's IP address in it, &lt;code&gt;ansible_ssh_pass&lt;/code&gt; stores the SSH password for each server, this shouldn't be used in production apps as it exposes your password.&lt;/p&gt;

&lt;h3&gt;
  
  
  Let's ping target01
&lt;/h3&gt;

&lt;p&gt;Run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ansible target01 -m ping -i inventory.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see this output if it was successful;&lt;/p&gt;

&lt;p&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%2Fjyr3qarmk9jswwq3wlj7.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%2Fjyr3qarmk9jswwq3wlj7.png" alt="Ansible ping"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you can't, verify the IP address you used for &lt;code&gt;target01&lt;/code&gt;, you can try pinging target02 too in the same way.&lt;/p&gt;

&lt;p&gt;Now we've only tried connecting to a server only one at a time, using &lt;code&gt;ansible target01 -m ping -i inventory.txt&lt;/code&gt;, we want to be able to run commands on multiple servers with a single command, let's edit our inventory file.&lt;/p&gt;

&lt;p&gt;You can use nano or VIM to edit the inventory file, if you'd like to learn about the VIM editor, check out my article, &lt;a href="https://dev.to/kennibravo/a-beginner-guide-on-how-to-use-the-vim-editor-on-linux-or-mac-2oc6"&gt;VIM for beginners&lt;/a&gt;, or use nano, by running &lt;code&gt;nano inventory.txt&lt;/code&gt; and edit the file to;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[targets]
target01 ansible_host=192.168.56.4 ansible_ssh_pass=vagrant
target02 ansible_host=192.168.56.5 ansible_ssh_pass=vagrant
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then &lt;code&gt;Ctrl X&lt;/code&gt; to Save and Exit.&lt;/p&gt;

&lt;p&gt;Now run;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ansible targets -m ping -i inventory.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see;&lt;/p&gt;

&lt;p&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%2F1nhx3anhbg3j2vefkwme.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%2F1nhx3anhbg3j2vefkwme.png" alt="Ansible targets"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We got two outputs, this is from each target (target01 and target02).&lt;/p&gt;

&lt;h3&gt;
  
  
  Quick explanation
&lt;/h3&gt;

&lt;p&gt;In the &lt;code&gt;inventory.txt&lt;/code&gt;, we created a group called &lt;code&gt;targets&lt;/code&gt; and added the &lt;code&gt;target01 and target02&lt;/code&gt; configuration; that's why we can run &lt;code&gt;ansible targets -m ping -i inventory.txt&lt;/code&gt; and it runs on all servers under the &lt;code&gt;targets&lt;/code&gt; group.&lt;/p&gt;

&lt;p&gt;But there's a better way to automate tasks on Servers!&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction to Ansible Playbooks
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Based on docs.ansible.com. Ansible Playbooks offer a repeatable, reusable, simple configuration management and multi-machine deployment system that is well suited to deploying complex applications. If you need to execute a task with Ansible more than once, write a playbook and put it under source control. Then you can use the playbook to push out new configurations or confirm the configuration of remote systems.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Let's create an Ansible Playbook
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nano Ansible-play.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Paste this;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- name: Play one
  hosts: targets
  tasks:
    - name: "Execute IP Check"
      command: ifconfig
      register: command_output
    - debug : var=command_output
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then run the playbook and attach the inventory file to it;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ansible-playbook exampleplaybook.yml -i inventory.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Explanation
&lt;/h3&gt;

&lt;p&gt;The whole YAML file is the playbook, under it, we have each play (activities/tasks that run on the server); we named it &lt;code&gt;Play one&lt;/code&gt;, also we used &lt;code&gt;targets&lt;/code&gt; as the hosts - This is our group from the inventory file, so we targetted all servers under the &lt;code&gt;targets&lt;/code&gt; group. Then we have each task that will run in the server under the &lt;code&gt;tasks&lt;/code&gt; list.&lt;/p&gt;

&lt;h3&gt;
  
  
  The first task explanation
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- name: "Execute IP Check"
  command: ifconfig
  register: command_output
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We gave it a name and used the &lt;code&gt;command&lt;/code&gt; module to run the &lt;code&gt;ifconfig&lt;/code&gt; command, then registered the output in a variable named &lt;code&gt;command_output&lt;/code&gt;. &lt;/p&gt;

&lt;h3&gt;
  
  
  The second task explanation
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- debug : var=command_output
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We then used the &lt;code&gt;debug&lt;/code&gt; module to redirect the &lt;code&gt;command_output&lt;/code&gt; to the stdout of the host (your PC).&lt;/p&gt;

&lt;p&gt;So, in summary, we ran all the &lt;code&gt;ifconfig&lt;/code&gt; commands on all the servers under the &lt;code&gt;targets&lt;/code&gt; group and got their outputs. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;BUT there's a better way to copy files from a source(your PC) to a destination(nodecontroller) through SSH.&lt;/strong&gt;&lt;br&gt;
SCP is the solution.. 😉 &lt;br&gt;
I was hoping you wouldn't ask me the whole meaning; I forgot, lol. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  How to use SCP
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Secure Copy(SCP)&lt;/strong&gt; is used to securely transfer files through the SSH protocol from one computer to another. &lt;/p&gt;

&lt;p&gt;You want to be able to edit your Ansible playbook on your PC(host), so you can use a text editor like VSCode; when you're done editing it, you can transfer it to the nodecontroller VM with a single command instead of using that ugly nano or copying from your host to the VM, this is a better alternative and faster and we get to learn something more.&lt;/p&gt;

&lt;h2&gt;
  
  
  Install SCP Plugin in Vagrant
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;vagrant plugin install vagrant-scp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's all; now we're ready to use SCP. &lt;/p&gt;

&lt;h3&gt;
  
  
  Format of the SCP command
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;vagrant scp &amp;lt;source&amp;gt; &amp;lt;destination&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In your host(PC), change the directory to where you have your ansible playbook, then run this command;&lt;/p&gt;

&lt;p&gt;Using it;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;vagrant scp absolute_uri_to_playbook/playbook.plays.yaml nodecontroller:/home/vagrant
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This copies the playbook on your host to the &lt;code&gt;nodecontroller&lt;/code&gt; using just a single command, so when you make new changes to the playbook on your host, rerun that same command; SCP is not only on Vagrant; you can also use it without Vagrant.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are Ansible Modules?
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Based on docs.ansible.com, Modules (also referred to as “task plugins” or “library plugins”) are discrete units of code that can be used from the command line or in a playbook task. Ansible executes each module, usually on the remote managed node, and collects return values.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We've used two modules so far; we used the &lt;code&gt;command&lt;/code&gt; and the &lt;code&gt;debug&lt;/code&gt; module, modules is the building block you build upon on playbooks, want to install apache on 250+ Ubuntu Linux server? Use the apt module for Ansible. &lt;/p&gt;

&lt;h2&gt;
  
  
  Install PHP/MYSQL and Apache on all VMs using Ansible Playbook
&lt;/h2&gt;

&lt;p&gt;It's alright if you don't know PHP, follow along. Let's assume you have to configure the LAMP stack for about 200+ systems running Linux, you can do that using Ansible with a playbook; it takes just a single command.&lt;/p&gt;

&lt;p&gt;Create a playbook in your nodecontroller and name it &lt;code&gt;playbook.plays.yaml&lt;/code&gt;, you can name it anything you like. &lt;/p&gt;

&lt;h3&gt;
  
  
  In playbook.plays.yaml
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- name: Play one
  hosts: targets
  tasks:
    - apt_repository:
        repo: ppa:ondrej/php
        state: present
      become: yes

    - name: Install Apache2
      apt:
        name: apache2
        state: present

      become: yes
    - name: Install MySQL Server
      apt:
        name: mysql-server
        state: present
      become: yes
    - name: Install PHP and others
      become: yes
      apt:
        pkg:
          - php5
          - libapache2-mod-php5
          - php5-mysql

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

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; Don't use PHP5 on a production app; I only used it for illustration, I was having issues installing PHP7, so I had to go with the quick one. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Quick explanation
&lt;/h3&gt;

&lt;p&gt;We used the &lt;code&gt;targets&lt;/code&gt; group as the hosts, which contains &lt;code&gt;target01&lt;/code&gt; and &lt;code&gt;target02&lt;/code&gt;. The first task we added adds the &lt;code&gt;ppa:ondrej/php&lt;/code&gt; repository using the &lt;code&gt;apt_repository&lt;/code&gt; module, we'd have used &lt;code&gt;sudo add-apt-repository ppa:ondrej/php5&lt;/code&gt; to do this on a terminal, we also used a field &lt;code&gt;become: yes&lt;/code&gt;, this is used to elevate privileges, that is using sudo. &lt;/p&gt;

&lt;p&gt;Then we used the &lt;code&gt;apt&lt;/code&gt; module to install &lt;code&gt;mysql-server&lt;/code&gt;, then used a field &lt;code&gt;state: present&lt;/code&gt;, this means &lt;code&gt;mysql-server should be present&lt;/code&gt;, if it was already installed, it does nothing, and if it wasn't installed, it installs it, so you can run this as many times as you want.&lt;/p&gt;

&lt;p&gt;We did same for &lt;code&gt;apache2&lt;/code&gt;, in the last module, we installed a list of packages, &lt;code&gt;php5, libapache2-mod-php5, php5-mysql&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now you can run it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ansible-playbook playbook.plays.yaml -i inventory.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If it was successful, you should see something like;&lt;/p&gt;

&lt;p&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%2Fncebnwmtrfxhymfx5y95.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%2Fncebnwmtrfxhymfx5y95.png" alt="Ansible vagrant"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This means you have installed PHP and MySQL on target01 and target02 without actually interacting with either of them, now imagine it was about 100 virtual machines. &lt;/p&gt;

&lt;p&gt;There are more to working with Ansible to this, also our PHP and MySQL setup isn't done yet, I just went through the basics in this article, maybe, just maybe in the future, I might create a complete tutorial to do that. &lt;/p&gt;

&lt;p&gt;This brings us to the end of this long article, I hope you enjoyed it, if you did, consider sharing and/or adding a Reaction, if you had any issues, you can also add a comment here, I would try my best to help.&lt;/p&gt;

&lt;p&gt;Thanks for reading. &lt;/p&gt;

</description>
      <category>devops</category>
      <category>cloud</category>
      <category>php</category>
      <category>linux</category>
    </item>
    <item>
      <title>How to Create and Automate Virtual Machines using Vagrant</title>
      <dc:creator>Kehinde Alade</dc:creator>
      <pubDate>Mon, 17 Oct 2022 10:01:42 +0000</pubDate>
      <link>https://dev.to/kennibravo/vagrant-for-beginners-getting-started-with-examples-jlm</link>
      <guid>https://dev.to/kennibravo/vagrant-for-beginners-getting-started-with-examples-jlm</guid>
      <description>&lt;p&gt;Vagrant is an automation tool that helps in easily creating virtual machines and automating them while saving time and increasing productivity. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Based on &lt;a href="https://www.vagrantup.com/intro" rel="noopener noreferrer"&gt;https://www.vagrantup.com/intro&lt;/a&gt;, Vagrant is a tool for building and managing virtual machine environments in a single workflow. With an easy-to-use workflow and focus on automation, Vagrant lowers development environment setup time, increases production parity, and makes the "works on my machine" excuse a relic of the past.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Have you ever used VirtualBox or VMWare before? Vagrant helps us automate and quickly build the things you'd have used VirtualBox for; sounds easy, I know, right? &lt;/p&gt;

&lt;p&gt;We'd be learning about Vagrant by using it with Ansible; what is Ansible?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Ansible is an IT automation tool. It can configure systems, deploy software, and orchestrate more advanced IT tasks such as continuous deployments or zero downtime rolling updates.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Ever thought of writing a script to automate something for you using Python or Golang? Ansible helps you do that without writing actual codes; YAML is the language ansible understands. &lt;/p&gt;

&lt;p&gt;Even though I've tried to make this article as beginner-level as it could be, there are still some requirements;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;YAML (basics)&lt;/li&gt;
&lt;li&gt;Docker (basics)&lt;/li&gt;
&lt;li&gt;Linux&lt;/li&gt;
&lt;li&gt;Basics of VirtualBox&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So what's the point of this article? What do we want to use Ansible and Vagrant for?&lt;/p&gt;

&lt;p&gt;We would use Vagrant to create three remote Virtual Machines using Virtual Box and automate tasks using Ansible on the VMs. &lt;/p&gt;

&lt;p&gt;The three VMs are;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The Controller VM:&lt;/strong&gt; This controls other targets VMs and automates tasks using Ansible, so, Ansible will be installed on the Controller VM.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Target 1 and Target 2 VMs&lt;/strong&gt;: These are the target VMs; we'd use the Controller VM to automate tasks in these target VMS.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now, let's dive right in and install Vagrant. &lt;/p&gt;

&lt;h2&gt;
  
  
  Install Vagrant on your PC
&lt;/h2&gt;

&lt;p&gt;Visit &lt;a href="https://www.vagrantup.com/downloads" rel="noopener noreferrer"&gt;https://www.vagrantup.com/downloads&lt;/a&gt; and download; you can use the executable file for Windows OR use brew for Mac; it's available for Mac, Linux and Windows.&lt;/p&gt;

&lt;p&gt;After downloading and installing it, to confirm, run;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

vagrant --version


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

&lt;/div&gt;

&lt;p&gt;Also, install VirtualBox, &lt;a href="https://www.virtualbox.org/wiki/Downloads" rel="noopener noreferrer"&gt;https://www.virtualbox.org/wiki/Downloads&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using Vagrant to create the VMs (Controller VMs and Targets)
&lt;/h2&gt;

&lt;p&gt;As a &lt;code&gt;Dockerfile&lt;/code&gt; is to Docker, a &lt;code&gt;Vagrantfile&lt;/code&gt; is for Vagrant; inside a Vagrantfile is where we configure the VM we want to use, so open your text editor and create a Vagrantfile&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Vagrantfile&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

NUM_NODES = 2
NUM_CONTROLLER_NODE = 1
IP_NTW = "192.168.56."
CONTROLLER_IP_START = 2
NODE_IP_START = 3


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

&lt;/div&gt;

&lt;p&gt;We created a few variables quick explanation about them.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;NUM_NODES&lt;/strong&gt;: This is the number of nodes(target VMs) we want to create.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;NUM_CONTROLLER_NODE&lt;/strong&gt;: Number of Controller nodes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;IP_NTW&lt;/strong&gt;: This is the network range we want the VMs to belong to, so our network will have the format of &lt;code&gt;192.168.56.{any_number}&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CONTROLLER_IP_START&lt;/strong&gt;: We specified the start number where the controller would be assigned to in the network, so our controller will start from &lt;code&gt;192.168.56.2&lt;/code&gt;, and the &lt;strong&gt;NODE_IP_START&lt;/strong&gt; will be starting from 3, that's &lt;code&gt;192.168.56.3&lt;/code&gt;. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These will all make sense in some moments. Let's continue for now. We'd be using an Ubuntu image, it's called Image in Docker, but it's called a Box in Vagrant; you can search for boxes at &lt;a href="https://app.vagrantup.com/boxes/search" rel="noopener noreferrer"&gt;https://app.vagrantup.com/boxes/search&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Vagrantfile&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

NUM_NODES = 2
NUM_CONTROLLER_NODE = 1
IP_NTW = "192.168.56."
CONTROLLER_IP_START = 2
NODE_IP_START = 3

Vagrant.configure("2") do |config|
    config.vm.box = "ubuntu/trusty64"

end


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

&lt;/div&gt;

&lt;p&gt;The 2 in vagrant.configure("2") specifies the configuration version, don't change it, we also used the &lt;code&gt;ubuntu/trusty64&lt;/code&gt; box, the &lt;code&gt;config&lt;/code&gt; is a local variable inside the vagrant.configure("2") directive, we use it to configure the box, like &lt;code&gt;config.vm.box = "ubuntu/trusty64"&lt;/code&gt;, this specifies the box we used. &lt;/p&gt;

&lt;h2&gt;
  
  
  Configuration for the Target VMs
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Vagrantfile&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

NUM_NODES = 2
NUM_CONTROLLER_NODE = 1
IP_NTW = "192.168.56."
CONTROLLER_IP_START = 2
NODE_IP_START = 3

Vagrant.configure("2") do |config|
    config.vm.box = "ubuntu/trusty64"

    (1..NUM_NODES).each do |i|
        config.vm.define "target0#{i}" do |node|
            node.vm.provider "virtualbox" do |vb|
                vb.name = "target0#{i}"
                vb.memory = 2048
                vb.cpus = 2
            end

            node.vm.hostname = "target0#{i}"
            node.vm.network "private_network", ip: IP_NTW + "#{NODE_IP_START + i}"
            node.vm.network "forwarded_port", guest: 22, host: "#{2720 + i}"
        end
end


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

&lt;/div&gt;

&lt;p&gt;We created the target VMs, and we already created a Variable called &lt;code&gt;NUM_NODES&lt;/code&gt;, so we created a foreach loop to loop from 1..NUM_NODES, and for each loop instance, we define the config for each target. Our counter variable is &lt;strong&gt;i&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Then we defined the name of the box &lt;strong&gt;config.vm.define "target0#{i}" do |node|&lt;/strong&gt;, in it, we set a provider of Virtualbox, Vagrant will use Virtualbox to set up the box, also expect our configs to be for Virtualbox, we then gave the box a name, set the memory to use, also the number of CPUs.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;node.vm.hostname = "target0#{i}"&lt;/code&gt; set the hostname, so the first target will be &lt;strong&gt;target01&lt;/strong&gt; and the second &lt;strong&gt;target02&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Next, we defined the networks.&lt;/p&gt;

&lt;p&gt;A quick network refresher.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;By default, all boxes in Vagrant use Adapter 1, which is the NAT; using NAT, our VMs can get their internet connections from the host(YOUR PC), but your VMs can't communicate with each other. &lt;/li&gt;
&lt;li&gt;In Vagrant, a &lt;strong&gt;private network&lt;/strong&gt; is the same as a &lt;strong&gt;Host-Only network&lt;/strong&gt;; a Host-Only network allows VMs on the same network to communicate with each other but can't communicate outside the network.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So combining NAT and a Host-Only network means our VMs can communicate with each other (since they're on the same network); also, they can get Internet Connectivity from the host using the NAT.&lt;/p&gt;

&lt;p&gt;Back to Vagrant, This line creates a private network(Host Only) &lt;code&gt;node.vm.network "private_network", ip: IP_NTW + "#{NODE_IP_START + i}"&lt;/code&gt;, also set the IP, it uses the &lt;code&gt;IP_NTW&lt;/code&gt; and adds the &lt;code&gt;NODE_IP_START&lt;/code&gt; variable and the current loop, poor little &lt;code&gt;i&lt;/code&gt;, we could have used the DHCP server to automatically assign IP address to our VMs, but we won't be covering that.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;node.vm.network "forwarded_port", guest: 22, host: "#{2720 + i}"&lt;/code&gt; this part defines a port forwarding, which is used to handle SSH connection; SSH connection uses the port 22 on all systems, so whenever the host receives a request on port &lt;code&gt;2720&lt;/code&gt;, it's routed to the VM on port 22(SSH), that's basically what port forwarding does, it forwards ports on the host to the VM in this case, using this you can SSH from your PC into the VMs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuration for the Controller VM(s)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Vagrantfile
&lt;/h3&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

NUM_NODES = 2
NUM_CONTROLLER_NODE = 1
IP_NTW = "192.168.56."
CONTROLLER_IP_START = 2
NODE_IP_START = 3

Vagrant.configure("2") do |config|
    config.vm.box = "ubuntu/trusty64"

    (1..NUM_NODES).each do |i|
        config.vm.define "target0#{i}" do |node|
            node.vm.provider "virtualbox" do |vb|
                vb.name = "target0#{i}"
                vb.memory = 2048
                vb.cpus = 2
            end

            node.vm.hostname = "target0#{i}"
            node.vm.network "private_network", ip: IP_NTW + "#{NODE_IP_START + i}"
            node.vm.network "forwarded_port", guest: 22, host: "#{2720 + i}"
        end
    end

    i = 0

    (1..NUM_CONTROLLER_NODE).each do [i] 
        config.vm.define "nodecontroller" do |node|
            node.vm.provider "virtualbox" do |vb|
                vb.name = "nodecontroller"
                vb.memory = 2048
                vb.cpus = 2
            end

            node.vm.hostname = "nodecontroller"
            node.vm.network "private_network", ip: IP_NTW + "#{CONTROLLER_IP_START + i}"
            node.vm.network "forwarded_port", guest: 22, host: "#{2710 + i}"
        end
    end
end


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

&lt;/div&gt;

&lt;p&gt;Starting from the comment &lt;code&gt;Configuration for Controller VM(s)&lt;/code&gt; down is where we did the config of the controller VM; there is nothing to explain here; both configs are similar. Your &lt;code&gt;Vagrantfile&lt;/code&gt; should be the same as this. &lt;/p&gt;

&lt;p&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%2F5e524bv5sszl384ahebo.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%2F5e524bv5sszl384ahebo.png" alt="Vagrant Ubuntu"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now let's run the Vagrantfile and set up the virtual machines, change the directory into where the Vagrantfile is then run.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

vagrant up


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

&lt;/div&gt;

&lt;p&gt;This would take a few minutes, so be patient; when it finishes, you can run &lt;code&gt;vagrant status&lt;/code&gt; to see the Virtual machines that were created.&lt;/p&gt;

&lt;p&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%2F1vwgm2eh21ofqr9le2lb.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%2F1vwgm2eh21ofqr9le2lb.png" alt="Vagrant status"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;You can also open your Virtualbox, and you would see the virtual machines there too.&lt;/p&gt;

&lt;p&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%2Fdfh6npan2itxn4qc315d.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%2Fdfh6npan2itxn4qc315d.png" alt="Virtualbox"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Working with the Virtual Machines
&lt;/h2&gt;

&lt;p&gt;Let's SSH into the &lt;code&gt;nodecontroller&lt;/code&gt;.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

vagrant ssh nodecontroller


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

&lt;/div&gt;

&lt;p&gt;If it requests a password, use &lt;code&gt;vagrant&lt;/code&gt; as the password for all the VMS.  &lt;/p&gt;

&lt;h3&gt;
  
  
  Get the IP address of &lt;code&gt;nodecontroller.&lt;/code&gt;
&lt;/h3&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

ifconfig


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

&lt;/div&gt;

&lt;p&gt;You should see (&lt;code&gt;192.168.56.2&lt;/code&gt;)&lt;/p&gt;

&lt;p&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%2Fs7yirae9ja1cnfaxtu8k.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%2Fs7yirae9ja1cnfaxtu8k.png" alt="ifconfig"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now exit &lt;code&gt;nodecontroller&lt;/code&gt;. &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

exit


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

&lt;/div&gt;
&lt;h3&gt;
  
  
  Let's get the IP addresses of target01 and target02
&lt;/h3&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

vagrant ssh target01


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

&lt;/div&gt;

&lt;p&gt;Run &lt;code&gt;ifconfig&lt;/code&gt; and exit, then repeat the same process for &lt;code&gt;target02&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;My IP addresses are; &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;target01: 192.168.56.4&lt;/li&gt;
&lt;li&gt;target02: 192.168.56.5&lt;/li&gt;
&lt;li&gt;nodecontroller: 192.168.56.2&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Yours could be different; you can notice they all end in &lt;code&gt;56.&lt;/code&gt; this means they're on the same network and can communicate. &lt;/p&gt;

&lt;h3&gt;
  
  
  SSH to target02 from target01
&lt;/h3&gt;

&lt;p&gt;First, SSH into target01.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

ssh 192.168.56.5


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

&lt;/div&gt;

&lt;p&gt;Try SSH all vice and versa, from target01-target02, target02-target01, nodecontroller-target01, nodecontroller-target02. &lt;/p&gt;

&lt;p&gt;Remember I said earlier that since we used a Host-Only network, we can communicate with other VMs on the same networks; let's try to SSH into &lt;code&gt;target01&lt;/code&gt; from &lt;code&gt;nodecontroller&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You can also test internet connectivity on all VMs; let's try pinging google.com.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

ping google.com


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

&lt;/div&gt;

&lt;p&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%2Frcd0z0u612k01d9er8m9.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%2Frcd0z0u612k01d9er8m9.png" alt="ping google"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now everything is set!&lt;/p&gt;

&lt;p&gt;However, installing Ansible and Automating Tasks would come in the Part 2 series of this article. This one is long enough, felt like I've been typing forever, lol.&lt;/p&gt;

&lt;p&gt;I know I said a lot in this article, I just wanted everyone to be able to follow along, including beginners, so I tried breaking everything down; hopefully, I didn't bore you.&lt;/p&gt;

&lt;p&gt;If you got this far, Add a Reaction and Follow me so you will get notified when I post part 2 of this article. &lt;/p&gt;

&lt;p&gt;Thanks for reading. 😀 &lt;/p&gt;

</description>
      <category>devops</category>
      <category>linux</category>
      <category>beginners</category>
      <category>cloud</category>
    </item>
    <item>
      <title>Pipeline 101 for PHP and Laravel Projects with Jenkins and Docker</title>
      <dc:creator>Kehinde Alade</dc:creator>
      <pubDate>Mon, 10 Oct 2022 13:56:51 +0000</pubDate>
      <link>https://dev.to/kennibravo/pipeline-101-for-php-and-laravel-projects-with-jenkins-and-docker-47gh</link>
      <guid>https://dev.to/kennibravo/pipeline-101-for-php-and-laravel-projects-with-jenkins-and-docker-47gh</guid>
      <description>&lt;p&gt;Few months ago, I was trying to setup a pipeline for a Laravel project that I was working on, but I encountered some issues, I wasn't able to get an article that explains the process to a beginner, the Whys and Hows you know, but I was able to get it done.&lt;/p&gt;

&lt;p&gt;In this article, I would explain the process like one would do to a beginner. &lt;/p&gt;

&lt;p&gt;Setting up a Pipeline for a PHP or a Laravel project is easier than you might think, the prerequisite for this article are;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Docker (Install docker on your computer, we'd be using a Jenkins image and setting up Laravel and PHP in the container).&lt;/li&gt;
&lt;li&gt;Jenkins (Don't install yet, we would be doing this later in the article).&lt;/li&gt;
&lt;li&gt;Basic understanding of Docker and Jenkins generally.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, let's get our hands dirty!&lt;/p&gt;

&lt;p&gt;First of all, we need to find a suitable Jenkins image that we can use, visit &lt;a href="https://hub.docker.com/search?q=jenkins" rel="noopener noreferrer"&gt;hub.docker.com&lt;/a&gt; and search for Jenkins. &lt;/p&gt;

&lt;p&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%2F70ygtz2la6fapr0y7xq6.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%2F70ygtz2la6fapr0y7xq6.png" alt="Docker Jenkins"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We would be using that one above, just get the tag you need, let's follow the steps below.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; Build our Jenkins Docker Container&lt;br&gt;
We need to Setup Jenkins on Docker and Install PHP and Laravel.&lt;/p&gt;

&lt;h3&gt;
  
  
  Open your text editor and Create a Dockerfile.
&lt;/h3&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

FROM jenkins/jenkins:centos7

USER root



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

&lt;/div&gt;

&lt;p&gt;We used the &lt;strong&gt;jenkins/jenkins:centos7&lt;/strong&gt;, this image is using cent-os based on RHEL (Red Hat Enterprise Linux), you can decide to use image tag you prefer. &lt;/p&gt;

&lt;p&gt;You can go ahead and build the image for now using &lt;code&gt;docker image build -t jenkins-laravel .&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The command builds the Dockerfile in your current directory &lt;strong&gt;(.)&lt;/strong&gt; then tag the image as &lt;strong&gt;jenkins-laravel&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2.&lt;/strong&gt; Setup PHP and Remi Repository in the Dockerfile&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

FROM jenkins/jenkins:centos7

USER root

RUN yum -y install epel-release
RUN rpm -Uvh http://rpms.famillecollet.com/enterprise/remi-release-7.rpm
RUN yum-config-manager --enable remi-php74
RUN yum install php php-mbstring php-xml php-pdo php-pdo_mysql php-xdebug -y
RUN yum update -y


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

&lt;/div&gt;

&lt;p&gt;We added few lines to the &lt;strong&gt;Dockerfile&lt;/strong&gt;, what the lines do is to setup the Remi RPM repository on cent-os, this allow us to be able to install PHP, and then install PHP on it.&lt;/p&gt;

&lt;p&gt;So far we have setup Jenkins and PHP on the same image, this means we can run PHP commands right from Jenkins Pipeline Console, but PHP is not enough, we need to install Composer too.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3.&lt;/strong&gt; Setting up Composer in the Dockerfile&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

FROM jenkins/jenkins:centos7

USER root

RUN yum -y install epel-release
RUN rpm -Uvh http://rpms.famillecollet.com/enterprise/remi-release-7.rpm
RUN yum-config-manager --enable remi-php74
RUN yum install php php-mbstring php-xml php-pdo php-pdo_mysql php-xdebug -y
RUN yum update -y
RUN cd /tmp
RUN curl -sS https://getcomposer.org/installer | php
RUN mv composer.phar /usr/local/bin/composer


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

&lt;/div&gt;

&lt;p&gt;The last few lines installs Composer, &lt;strong&gt;curl&lt;/strong&gt; downloads the composer file and pipes it to PHP CLI., then the last line, we moved the actual downloaded composer file, &lt;strong&gt;composer.phar&lt;/strong&gt; to &lt;strong&gt;/usr/local/bin/composer&lt;/strong&gt;, this makes composer to be able to run with just typing &lt;strong&gt;composer&lt;/strong&gt; in the terminal.&lt;/p&gt;

&lt;p&gt;Everything is setup now, run &lt;code&gt;docker image build -t jenkins-laravel .&lt;/code&gt;, we can now run PHP and composer commands right inside Jenkins Pipeline Console and this is all we need to setup Laravel. &lt;/p&gt;

&lt;p&gt;It might take a while to get those images, just be patient, when it finishes, continue the article. &lt;/p&gt;

&lt;p&gt;Now let us the launch our Container from the terminal with the new image we created.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

docker run -d -p 4000:8080 --name jenkins jenkins-laravel


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

&lt;/div&gt;

&lt;p&gt;This runs our created Jenkins Image tagged &lt;strong&gt;jenkins-laravel&lt;/strong&gt; in a detached mode and mapped the port 4000 on your host machine to the Container's port 8080. &lt;/p&gt;

&lt;p&gt;After running this command, you would see an output of strings, that is the container ID, this means our container is now running in detached mode.&lt;/p&gt;

&lt;p&gt;To access it, open your browser and visit &lt;a href="http://localhost:4000" rel="noopener noreferrer"&gt;http://localhost:4000&lt;/a&gt;, where &lt;strong&gt;4000&lt;/strong&gt; is the port you mapped to your container. &lt;/p&gt;

&lt;p&gt;You should see this screen if all went well.&lt;/p&gt;

&lt;p&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%2Fzrbrpr8qlnwxns9vtky2.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%2Fzrbrpr8qlnwxns9vtky2.png" alt="Jenkins"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Getting the Password for Jenkins
&lt;/h3&gt;

&lt;p&gt;Run &lt;code&gt;docker exec jenkins cat /var/jenkins_home/secrets/initialAdminPassword&lt;/code&gt;, copy the output and paste it in the password section on your Jenkins, then install suggested plugins.&lt;/p&gt;

&lt;p&gt;If you can see this then you are good to go.&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%2Fmie307ybnzdk44cxcxye.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%2Fmie307ybnzdk44cxcxye.png" alt="Jenkins home"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Let's create a Pipeline
&lt;/h2&gt;

&lt;p&gt;Click on &lt;strong&gt;New Item&lt;/strong&gt; on the Sidebar, give the Item a name and select &lt;strong&gt;Pipeline&lt;/strong&gt; then click on OK. &lt;/p&gt;

&lt;p&gt;Give it a description, just anything is OK for now.&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%2Fvvpwb6pfomsl3wgj3dy6.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%2Fvvpwb6pfomsl3wgj3dy6.png" alt="Jenkins description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Scroll down to the Pipeline section and make sure Pipeline Script is selected.&lt;/p&gt;

&lt;p&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%2F7e6jmblkbq16ngfft18t.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%2F7e6jmblkbq16ngfft18t.png" alt="Jenkins Pipeline"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Paste these codes in there.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

pipeline {
    agent any

    stages {
        stage('Build') {
            steps {
                git 'https://github.com/Kennibravo/jenkins-laravel.git'
                sh 'composer install'
                sh 'cp .env.example .env'
                sh 'php artisan key:generate'
            }
        }
        stage('Test') {
            steps {
                sh './vendor/bin/phpunit'
            }
        }
    }
}


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

&lt;/div&gt;
&lt;h3&gt;
  
  
  Quick explanation on what the codes actually does
&lt;/h3&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

    stages {
        stage('Build') {
            steps {
                git 'https://github.com/Kennibravo/jenkins-laravel.git'
                sh 'composer install'
                sh 'cp .env.example .env'
                sh 'php artisan key:generate'
            }
        }
        stage('Test') {
            steps {
                sh './vendor/bin/phpunit'
            }
        }
    }


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

&lt;/div&gt;

&lt;p&gt;The laravel project is just basic laravel boilerplate codes, nothing else. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Stages:&lt;/strong&gt; We defined all steps needed in our Pipeline here.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stage:&lt;/strong&gt; You can notice that we have two stage (Build and Test) inside the stages{} braces, in the Build stage, we cloned the &lt;a href="https://github.com/Kennibravo/jenkins-laravel.git" rel="noopener noreferrer"&gt;https://github.com/Kennibravo/jenkins-laravel.git&lt;/a&gt; github repo, then run &lt;strong&gt;composer install&lt;/strong&gt; and do other necessary things. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Don't forget we already installed Composer and Jenkins in the same container, so Jenkins can use the composer command. &lt;/p&gt;

&lt;p&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%2Fkxy7471nh497hoebydoi.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%2Fkxy7471nh497hoebydoi.png" alt="Jenkins pipeline"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After this, click on Save. &lt;/p&gt;

&lt;p&gt;It takes you here.&lt;/p&gt;

&lt;p&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%2F75gy5oallr44yj9s7e7a.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%2F75gy5oallr44yj9s7e7a.png" alt="Jenkins"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We've created our Pipeline, now we need to launch it, to launch it, click on &lt;strong&gt;Build Now&lt;/strong&gt; in the sidebar, then the Pipeline starts. &lt;/p&gt;

&lt;p&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%2Fwt1o8kvpzff76sxfgaf5.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%2Fwt1o8kvpzff76sxfgaf5.png" alt="Jenkins pipeline"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To see what's going on, click on that &lt;strong&gt;#1&lt;/strong&gt;, then Console Output. &lt;/p&gt;

&lt;p&gt;If your Pipeline was successful, you should see this.&lt;/p&gt;

&lt;p&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%2F9l0ioq07f1xxerqtd0z4.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%2F9l0ioq07f1xxerqtd0z4.png" alt="Jenkins pipeline"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can see the two stages we created, &lt;strong&gt;Build&lt;/strong&gt; and &lt;strong&gt;Test&lt;/strong&gt;, if the pipeline fails, try checking the Console Output to see what's wrong.&lt;/p&gt;

&lt;p&gt;Note that there are more to creating CI/CD pipelines to this, this article just covered the basics for you.&lt;/p&gt;

&lt;p&gt;This brings us to the end of this article, if you enjoyed, you can add a Reaction or drop a comment if you had any issues or questions. &lt;/p&gt;

&lt;p&gt;Thanks for reading. 😃 &lt;/p&gt;

</description>
      <category>php</category>
      <category>laravel</category>
      <category>devops</category>
      <category>webdev</category>
    </item>
    <item>
      <title>A Beginner Guide on How to Use the Vim Editor on Linux or Mac</title>
      <dc:creator>Kehinde Alade</dc:creator>
      <pubDate>Fri, 07 Oct 2022 14:43:49 +0000</pubDate>
      <link>https://dev.to/kennibravo/a-beginner-guide-on-how-to-use-the-vim-editor-on-linux-or-mac-2oc6</link>
      <guid>https://dev.to/kennibravo/a-beginner-guide-on-how-to-use-the-vim-editor-on-linux-or-mac-2oc6</guid>
      <description>&lt;p&gt;&lt;em&gt;OK, a quick Vi story.&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It's 1am in the morning in the year 2060, you could faintly hear the sound of a mechanical engine whirring, struggling to understand the situation, you opened your eyes and found yourself in a spaceship making a free fall towards the earth, while panicking you began to find the controls, fortunately you saw one, but it's a ugly black screen, on it is a white cursor blinking as if it were laughing at you cos you're in real mess, the spaceship is about to crash and you can't control it, the only thing you know about Vi are the memes you've once laughed at, hahaha.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--iFG9Pmsj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1661598229653/8Byh7m6_f.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--iFG9Pmsj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1661598229653/8Byh7m6_f.jpg" alt="Vim Memes" width="638" height="552"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Uhm, so back to business, Vi has two/three modes namely;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Command Mode&lt;/li&gt;
&lt;li&gt;Insert Mode&lt;/li&gt;
&lt;li&gt;Last line Mode&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Any command or explanation here will also work for VIM, which is an improved version of Vi.&lt;/p&gt;

&lt;p&gt;This is only a beginner guide so I won't be wasting your time with lot of stories, well, except that boring Vi story you read. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Command Mode:&lt;/strong&gt;&lt;br&gt;
This is often the most confused mode in Vi, you remember that time you mistakenly opened your Vi editor, then you start hitting all the keys on your keyboard, you were in the command mode, the command mode is the default mode in Vi, open up your terminal or CLI app then copy and paste this;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;echo "Here is the first file in VIM" &amp;gt;&amp;gt; firstText.txt

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

&lt;/div&gt;



&lt;p&gt;The above line just output the content &lt;em&gt;"Here is the first file in VIM"&lt;/em&gt; into the &lt;strong&gt;firstText.txt&lt;/strong&gt; file. &lt;/p&gt;

&lt;p&gt;Now let's open up the file using Vi.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;vi firstText.txt

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

&lt;/div&gt;



&lt;p&gt;And then boom that ugly and unattractive screen spuns up and it looks like this, mine is light, yours could be dark;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qqUWumuT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1661523157343/z_wl7fR5R.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qqUWumuT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1661523157343/z_wl7fR5R.png" alt="Vim" width="880" height="553"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As at this instance, we're currently in the &lt;strong&gt;Command Mode&lt;/strong&gt; because it is the default mode, in command mode, as opposed to normal text editors, you can't type or insert text in your file, you can only issue commands like Undo, Redo, Quit, Save, etc.&lt;/p&gt;

&lt;p&gt;You can move around in the command mode using your arrow keys. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5KMTqIvC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1661597820040/suJ1R39Wx.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5KMTqIvC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1661597820040/suJ1R39Wx.jpg" alt="arrow-keys.jpg" width="215" height="196"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's try out some commands in the command mode!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Delete character: &lt;strong&gt;x&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Press &lt;strong&gt;x&lt;/strong&gt;, this deletes the current character you're on and it looks like this;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6PpCkcSQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1661523691251/0FGDo4OGV.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6PpCkcSQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1661523691251/0FGDo4OGV.png" alt="Vim" width="880" height="563"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Keep on pressing &lt;strong&gt;x&lt;/strong&gt; until it deletes all characters and looks like this.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Pi_msoMk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1661523781080/p2jdqdtcU.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Pi_msoMk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1661523781080/p2jdqdtcU.png" alt="Vim" width="880" height="557"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's try to &lt;strong&gt;undo&lt;/strong&gt; the characters we deleted.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Undo: &lt;strong&gt;u&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Keep pressing &lt;strong&gt;u&lt;/strong&gt; till all the text appears.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vBvZ-LZm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1661523870858/WIJ1qOsHm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vBvZ-LZm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1661523870858/WIJ1qOsHm.png" alt="Vim" width="880" height="558"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Instead of pressing &lt;strong&gt;x&lt;/strong&gt; multiple time, you can just;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Delete whole line: &lt;strong&gt;dd&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Press &lt;strong&gt;dd&lt;/strong&gt; and it deletes the whole current line and looks like;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--DFjPoZtV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1661524045110/dTmiGgef3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DFjPoZtV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1661524045110/dTmiGgef3.png" alt="Vim" width="880" height="551"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can Undo the changes so all the text appears back.&lt;/p&gt;

&lt;p&gt;There are also other commands like;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Copy: &lt;strong&gt;yy&lt;/strong&gt; &lt;/li&gt;
&lt;li&gt;Paste: &lt;strong&gt;p&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Commands aside, let's continue to the other mode, we'd be seeing lot of commands, continue reading.&lt;/p&gt;

&lt;p&gt;So far, we've played around in the command mode, but never for once did we actually insert data, uhm, can we not insert data like we will in a GUI text editor?&lt;/p&gt;

&lt;p&gt;Yeah, you guessed right!&lt;/p&gt;

&lt;p&gt;We can't!&lt;/p&gt;

&lt;p&gt;Sorry, I mean we can, just kidding.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Insert Mode:&lt;/strong&gt;&lt;br&gt;
In this mode, you can insert data as you would in a GUI text editor, but how do we get to this mode? I mean we can't insert data in Command mode.&lt;/p&gt;

&lt;p&gt;From command mode, there are lot of ways we can goto the Insert mode, one is pressing &lt;strong&gt;i&lt;/strong&gt; on your PC. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--liJsk--V--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1661524797222/I-JPUilaQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--liJsk--V--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1661524797222/I-JPUilaQ.png" alt="Vim" width="880" height="573"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We're currently in the command mode in the image above, you can try type stuffs here but it won't go through until you goto Insert mode, so press &lt;strong&gt;i&lt;/strong&gt; (small letter 'i') to switch to Insert mode;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PajI2zc0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1661524958840/CQoD3C68c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PajI2zc0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1661524958840/CQoD3C68c.png" alt="Vim" width="880" height="562"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Bottom left in the terminal, you can notice a *&lt;em&gt;-- INSERT -- *&lt;/em&gt;, this means we're currently in the Insert mode and can now start typing.&lt;/p&gt;

&lt;p&gt;In Insert mode, you can type as you would type in a normal text editor.&lt;/p&gt;

&lt;p&gt;Your &lt;em&gt;backspace&lt;/em&gt; key would work, even &lt;strong&gt;Ctrl + C&lt;/strong&gt; to &lt;strong&gt;Copy&lt;/strong&gt; and &lt;strong&gt;Ctrl + V&lt;/strong&gt; for &lt;strong&gt;Paste&lt;/strong&gt; even the &lt;strong&gt;Enter&lt;/strong&gt; key and others would work, so you can play around in here. &lt;/p&gt;

&lt;p&gt;Let's try adding more data into the file and save it, erase all data in the file and type;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This is to test out the Insert Mode&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Type it yourself, don't copy it from here.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--JTgEWVv1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1661525412390/Ztp_47uOk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--JTgEWVv1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1661525412390/Ztp_47uOk.png" alt="Vim" width="880" height="553"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's try to save the file and exit Vi.&lt;/p&gt;

&lt;p&gt;We need to go back to the &lt;strong&gt;Command Mode&lt;/strong&gt; in order to save this file and exit the editor, since we can switch to Insert Mode from Command Mode by pressing &lt;strong&gt;i&lt;/strong&gt;, how do we go back to the Command mode?&lt;/p&gt;

&lt;p&gt;Very easy! just hit your &lt;strong&gt;ESC&lt;/strong&gt; key(while in insert mode) on your PC.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--89uLa1ug--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1661525666546/8sDdWRDTx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--89uLa1ug--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1661525666546/8sDdWRDTx.png" alt="Vim" width="880" height="548"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we're back to the Command Mode. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Save: &lt;strong&gt;:w&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Quit: &lt;strong&gt;:q&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Save and Quit Vi: &lt;strong&gt;:wq&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Quit without saving: &lt;strong&gt;:q!&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's try to Save and Quit Vi, press &lt;strong&gt;:wq&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9NvkuWIP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1661525871705/gTZQsEnAE.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9NvkuWIP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1661525871705/gTZQsEnAE.png" alt="Vim" width="880" height="569"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt;: Whenever you press &lt;strong&gt;:&lt;/strong&gt; while in Command Mode, it takes you to the &lt;strong&gt;Last Line Mode&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;After you've typed in &lt;strong&gt;:wq&lt;/strong&gt;, hit the &lt;strong&gt;Enter&lt;/strong&gt; key.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uvDprRGg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1661526045354/72IKO1RCo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uvDprRGg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1661526045354/72IKO1RCo.png" alt="Vim" width="880" height="567"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And boom! We're Saved and exited Vi.&lt;/p&gt;

&lt;p&gt;Let's verify the changes we made to the &lt;strong&gt;firstText.txt&lt;/strong&gt; in our terminal.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cat firstText.txt

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

&lt;/div&gt;



&lt;p&gt;Here is the output, &lt;strong&gt;cat&lt;/strong&gt; is used to output the content of a file.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cnvt27JX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1661526235673/gBAOHc0gQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cnvt27JX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1661526235673/gBAOHc0gQ.png" alt="Vim" width="880" height="534"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can also use Vi to create a file and edit it immediately.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;vi secondText.txt

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

&lt;/div&gt;



&lt;p&gt;This creates the &lt;strong&gt;secondText.txt&lt;/strong&gt; file and open with Vi. &lt;/p&gt;

&lt;p&gt;This is the only basics you have to know to start using Vi, I attached a cheatsheet to this article so you can get more shortcuts from it.&lt;/p&gt;

&lt;p&gt;Here is a link to a Cheatsheet: &lt;a href="https://cheatography.com/ericg/cheat-sheets/vi-editor/pdf/"&gt;https://cheatography.com/ericg/cheat-sheets/vi-editor/pdf/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that you can use Vi, you can go on and brag to your friends and even pick up girls with it, I mean who doesn't love someone who can use Vi. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qv7kjZaL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1661598117268/URZgmlnIq.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qv7kjZaL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1661598117268/URZgmlnIq.jpeg" alt="Vim meme" width="640" height="503"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Takeaways from this article.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Command Mode is the default mode for Vi&lt;/li&gt;
&lt;li&gt;Use &lt;strong&gt;i&lt;/strong&gt; to switch to Insert Mode from Command Mode&lt;/li&gt;
&lt;li&gt;Use &lt;strong&gt;ESC&lt;/strong&gt; key to switch back to Command Mode from Insert Mode&lt;/li&gt;
&lt;li&gt;Typing &lt;strong&gt;:&lt;/strong&gt; in the command mode takes you to the Last Line Mode, you can then Save, Quit the file&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So this brings us to the end of this article, I would making articles on Linux and DevOps generally, so keep close tab. &lt;/p&gt;

&lt;p&gt;If you enjoyed the article, add a reaction for me. 😊&lt;/p&gt;

&lt;p&gt;Keep Vi-ing high and Cheers!&lt;/p&gt;

</description>
      <category>linux</category>
      <category>vim</category>
      <category>python</category>
      <category>devops</category>
    </item>
  </channel>
</rss>
