After being a regular reader of this blog for months, I’m thrilled to publish my first post!

Vim is a very powerful editing tool to know in Linux and sometimes the only text editor available when connected to a machine using command line interface.
Regarding the CKA exam, it is the text editor selected to be used and so knowing a few tricks can save you precious time for completing the various tasks requested.
This post assume you already have a basic knowledge of Vi/Vim and don’t have a panic attack because you don’t know how to exit Vim ;-). For beginners, the Vim package comes with a tutorial where you can learn the basics, just enter the command vimtutor in your terminal and follow the instructions.
Let’s start with some easy tips first before pushing it a bit harder.

Move to a pattern and modify text between double quotes

In the pod yaml file below we would like to change the mountPath value to /var/www/html

apiVersion: v1
kind: Pod
metadata:
  name: task-pv-pod
spec:
  volumes:
    - name: task-pv-storage
      persistentVolumeClaim:
        claimName: task-pv-claim
  containers:
    - name: task-pv-container
      image: nginx
      ports:
        - containerPort: 80
          name: "http-server"
      volumeMounts:
        - mountPath: "/usr/share/nginx/html"
          name: task-pv-storage

Let’s for example go straight to the mountPath key by typing /mountPath then press W (capital w) to reach the opening “

Now to delete everything between the “” and enter in insert mode type ci”

apiVersion: v1
kind: Pod
metadata:
  name: task-pv-pod
spec:
  volumes:
    - name: task-pv-storage
      persistentVolumeClaim:
        claimName: task-pv-claim
  containers:
    - name: task-pv-container
      image: nginx
      ports:
        - containerPort: 80
          name: "http-server"
      volumeMounts:
        - mountPath: ""
          name: task-pv-storage

All the content between the “” have been deleted and you can now just enter the new desired path here /var/www/html and save the file.

Split the screen

It is sometimes convenient to stay in Vim and do other system operations at the same time without exiting Vim. Here are some examples and ideas for doing so.

When editing a file with Vim you can split the screen vertically or horizontally with :vsp or :sp

apiVersion: v1                          |apiVersion: v1
kind: Pod                               |kind: Pod
metadata:                               |metadata:
  name: task-pv-pod                     |  name: task-pv-pod
spec:                                   |spec:
  volumes:                              |  volumes:
    - name: task-pv-storage             |    - name: task-pv-storage
      persistentVolumeClaim:            |      persistentVolumeClaim:
        claimName: task-pv-claim        |        claimName: task-pv-claim
  containers:                           |  containers:
    - name: task-pv-container           |    - name: task-pv-container
      image: nginx                      |      image: nginx
      ports:                            |      ports:
        - containerPort: 80             |        - containerPort: 80
          name: "http-server"           |          name: "http-server"
      volumeMounts:                     |      volumeMounts:
        - mountPath: "/usr/share/nginx/h|        - mountPath: "/usr/share/nginx/
tml"                                    |html"
          name: task-pv-storage         |          name: task-pv-storage
~                                       |~
~                                       |~
~                                       |~
~                                       |~
pod1.yaml                                pod1.yaml

By default the second area on the right (vertical split is used in this example) shows the same file as the first one. Each areas can be split further vertically or horizontally if required. Use CTRL+ww to switch between the areas and :q in an area to close it.

Now we can check a local file to open by switching to the shell (without exiting Vim) with :sh (note that this action will be in full screen and is not contained in a particular area). Here you can launch any system command as well as kubectl commands which is very handy for getting quickly an information. Here look for example for a file to edit, copy its name and exit from the shell with exit

Open now that new file in the second area with :e <file_name>. In my example I’ve opened pod2.yaml which has the same content as pod1.yaml for now but will be modified to evolve to a version 2 of that file.

apiVersion: v1                          |apiVersion: v1
kind: Pod                               |kind: Pod
metadata:                               |metadata:
  name: task-pv-pod                     |  name: task-pv-pod
spec:                                   |spec:
  volumes:                              |  volumes:
    - name: task-pv-storage             |    - name: task-pv-storage
      persistentVolumeClaim:            |      persistentVolumeClaim:
        claimName: task-pv-claim        |        claimName: task-pv-claim
  containers:                           |  containers:
    - name: task-pv-container           |    - name: task-pv-container
      image: nginx                      |      image: nginx
      ports:                            |      ports:
        - containerPort: 80             |        - containerPort: 80
          name: "http-server"           |          name: "http-server"
      volumeMounts:                     |      volumeMounts:
        - mountPath: "/usr/share/nginx/h|        - mountPath: "/var/www/html"
tml"                                    |          name: task-pv-storage
          name: task-pv-storage         |~
~                                       |~
~                                       |~
~                                       |~
~                                       |~
pod1.yaml                                pod2.yaml

You can now compare those files, copy/paste some text from one area to the other,…

To copy/paste you can trivially use the mouse or CTRL+C/CTRL+V between the areas but for the Vim purists you can use “+y and “+p to copy and paste to and from the system clipboard register. From my experience it doesn’t work well in all systems (especially in remote access) so I let you experiment with it.

Finally if you want to replace the name nginx by web in the second area, just use the search and replace command in that area only with :%s/nginx/web/gc

apiVersion: v1                          |apiVersion: v1
kind: Pod                               |kind: Pod
metadata:                               |metadata:
  name: task-pv-pod                     |  name: task-pv-pod
spec:                                   |spec:
  volumes:                              |  volumes:
    - name: task-pv-storage             |    - name: task-pv-storage
      persistentVolumeClaim:            |      persistentVolumeClaim:
        claimName: task-pv-claim        |        claimName: task-pv-claim
  containers:                           |  containers:
    - name: task-pv-container           |    - name: task-pv-container
      image: nginx                      |      image: web
      ports:                            |      ports:
        - containerPort: 80             |        - containerPort: 80
          name: "http-server"           |          name: "http-server"
      volumeMounts:                     |      volumeMounts:
        - mountPath: "/usr/share/nginx/h|        - mountPath: "/var/www/html"
tml"                                    |          name: task-pv-storage
          name: task-pv-storage         |~
~                                       |~
~                                       |~
~                                       |~
~                                       |~
pod1.yaml                                pod2.yaml [+]

Copy and insert a block and the use of the registers

Kubernetes manifest files are based on Yaml formatting and it is often useful to be able to copy a block as a container and copy it in order to create a second one.

There are several ways for doing this, let’s explore the most straightforward in my opinion:

First display the line numbers in vim with :set nu

  1 apiVersion: v1
  2 kind: Pod
  3 metadata:
  4   name: task-pv-pod
  5 spec:
  6   volumes:
  7     - name: task-pv-storage
  8       persistentVolumeClaim:
  9         claimName: task-pv-claim
 10   containers:
 11     - name: task-pv-container
 12       image: nginx
 13       ports:
 14         - containerPort: 80
 15           name: "http-server"
 16       volumeMounts:
 17         - mountPath: "/usr/share/nginx/html"
 18           name: task-pv-storage

If we want to copy the container from line 11 to line 15 included then type :11,15y (y stand for yank which means copy in Vim terminology, note also that using d instead of y would just have deleted that block)

Then go to line 15 (as you want to insert that copied block just after that line) with 15gg and paste the copied block with p (p stand for paste)

  1 apiVersion: v1
  2 kind: Pod
  3 metadata:
  4   name: task-pv-pod
  5 spec:
  6   volumes:
  7     - name: task-pv-storage
  8       persistentVolumeClaim:
  9         claimName: task-pv-claim
 10   containers:
 11     - name: task-pv-container
 12       image: nginx
 13       ports:
 14         - containerPort: 80
 15           name: "http-server"
 16     - name: task-pv-container
 17       image: nginx
 18       ports:
 19         - containerPort: 80
 20           name: "http-server"
 21       volumeMounts:
 22         - mountPath: "/usr/share/nginx/html"
 23           name: task-pv-storage

The second container is now properly inserted and can be modified further to match the requirements for it.

Note that when you yank or delete something (a character, a word, a line,…) in Vim it is stored in an unnamed register that is replaced after each yank or delete operation. Vim also offers 26 additional registers for users that corresponds to each 26 letters of the alphabet. It is then possible to copy something into different registers and paste the one desired by calling its register letter.

Let’s see an example of this where I want to copy the line with the name of the container in the register a and the line with the image of the container in the register b.

To do so type

11gg then “ayy           => This will copy line 11 into the register a

12gg then “byy           => This will copy line 12 into the register b

Then go to line 20 with 20gg as you will paste your copied lines after it and type:

“ap”bp in order to paste the content of register a then register b with the result shown below:

  1 apiVersion: v1
  2 kind: Pod
  3 metadata:
  4   name: task-pv-pod
  5 spec:
  6   volumes:
  7     - name: task-pv-storage
  8       persistentVolumeClaim:
  9         claimName: task-pv-claim
 10   containers:
 11     - name: task-pv-container
 12       image: nginx
 13       ports:
 14         - containerPort: 80
 15           name: "http-server"
 16     - name: task-pv-container
 17       image: nginx
 18       ports:
 19         - containerPort: 80
 20           name: "http-server"
 21     - name: task-pv-container
 22       image: nginx
 23       volumeMounts:
 24         - mountPath: "/usr/share/nginx/html"

That will create a third container in this pod to work with.

Note that both lines could have been copied at once as shown previously but that example was for education purpose only.

Note also that if you use just p you still have in the unnamed register the block you’ve copied at the beginning.

Use Visual Block to shift blocks at once

Now let’s push it a bit further and use Visual Block to shift blocks to the left or to the right. Yaml format is strict on the indentation of the elements and often it is required to move a block further to the right or to the left to match those Yaml requirements. When there are several lines to move we could do much better than using x to delete a character or i and space to insert one so let’s see how by using a common scenario: You’ve copied some lines from the Kubernetes documentation and paste them into your yaml file, however the pasting didn’t keep all the formatting very well as shown below:

  1 apiVersion: v1
  2 kind: Pod
  3 metadata:
  4   name: cpu-demo
  5   namespace: cpu-example
  6 spec:
  7   containers:
  8      - name: cpu-demo-ctr
  9        image: vish/stress
 10        resources:
 11          limits:
 12            cpu: "1"
 13          requests:
 14            cpu: "0.5"
 15        args:
 16        - -cpus
 17        - "2"

I’ve copied the container elements from line 8 to 17 and we can see that it is not properly aligned: The – before name at line 8 should be exactly below the c of containers above. However all that block itself is properly indented so we just need to shift all that block 3 characters to the left. To do so we go to line 8 with 8gg then type 0 to go at the beginning of the line and enter Visual Block with CTRL+v then use j (or down arrow key) to go down the last line then stroke l (or the right arrow key) 3 times.

Then press d to delete that whole block and see it now properly positioned:

  1 apiVersion: v1
  2 kind: Pod
  3 metadata:
  4   name: cpu-demo
  5   namespace: cpu-example
  6 spec:
  7   containers:
  8   - name: cpu-demo-ctr
  9     image: vish/stress
 10     resources:
 11       limits:
 12         cpu: "1"
 13       requests:
 14         cpu: "0.5"
 15     args:
 16     - -cpus
 17     - "2"

Now let’s have a look at the opposite scenario where the block needs to be pushed to the right:

  1 apiVersion: v1
  2 kind: Pod
  3 metadata:
  4   name: cpu-demo
  5   namespace: cpu-example
  6 spec:
  7   containers:
  8  - name: cpu-demo-ctr
  9    image: vish/stress
 10    resources:
 11      limits:
 12        cpu: "1"
 13      requests:
 14        cpu: "0.5"
 15    args:
 16    - -cpus
 17    - "2"

We can see now that the same container block needs to be pushed with one space character to the right in order to match the Yaml requirements.

Go to the beginning of line 8 as shown previously and enter Visual Block mode again with CTRL+v then use j (or down arrow key) to go down the last line (to select the block you want to work with) then type SHIFT+i then SPACE

  1 apiVersion: v1
  2 kind: Pod
  3 metadata:
  4   name: cpu-demo
  5   namespace: cpu-example
  6 spec:
  7   containers:
  8   - name: cpu-demo-ctr
  9    image: vish/stress
 10    resources:
 11      limits:
 12        cpu: "1"
 13      requests:
 14        cpu: "0.5"
 15    args:
 16    - -cpus
 17    - "2"

Line 8 is now properly positioned so type ESC twice and it’s almost magical but all the lines of the defined block will also move by one space to the right automatically:

  1 apiVersion: v1
  2 kind: Pod
  3 metadata:
  4   name: cpu-demo
  5   namespace: cpu-example
  6 spec:
  7   containers:
  8   - name: cpu-demo-ctr
  9     image: vish/stress
 10     resources:
 11       limits:
 12         cpu: "1"
 13       requests:
 14         cpu: "0.5"
 15     args:
 16     - -cpus
 17     - "2"

The whole block is now properly aligned!

Last but not least

If the editing goes wrong at some point, don’t panic and press ESC then u in order to undo the last operation and continue to press u in order to further undo. If you went too far in the undo then press CTRL+r in order to replay that last action and you can also go further in the replay by repeating that sequence.

Of course those Tips & Tricks are not limited to Kubernetes and CKA and can be used in any text editing context.

There are obviously much more as Vim possibilities look limitless but I hope you’ve learned something that can help you being more efficient with text editing by using Vim. This can be a game changer when passing the CKA exam, I’ve successfully passed it a few days ago and applying those Tips & Tricks allowed me to be quick and have time in the end to review my work.


Thumbnail [60x60]
by
Benoît Entzmann