Docker – Ubuntu – bash: ping: command not found

Docker images are pretty minimal, But you can install ping in your official ubuntu docker image via:

apt-get update
apt-get install iputils-ping

Chances are you dont need ping your image, and just want to use it for testing purposes. Above example will help you out.

But if you need ping to exist on your image, you can create a Dockerfile or commit the container you ran the above commands in to a new image.

Commit:

docker commit -m "Installed iputils-ping" --author "Your Name <name@domain.com>" ContainerNameOrId yourrepository/imagename:tag

Dockerfile:

FROM ubuntu
RUN apt-get update && apt-get install -y iputils-ping
CMD bash
Advertisements

Install kubernetes on Centos/RHEL 7

Kubernetes is a cluster and orchestration engine for docker containers. In other words Kubernetes is  an open source software or tool which is used to orchestrate and manage docker containers in cluster environment. Kubernetes is also known as k8s and it was developed by Google and donated to “Cloud Native Computing foundation”

In Kubernetes setup we have one master node and multiple nodes. Cluster nodes is known as worker node or Minion. From the master node we manage the cluster and its nodes using ‘kubeadm‘ and ‘kubectl‘  command.

Kubernetes can be installed and deployed using following methods:

  • Minikube ( It is a single node kubernetes cluster)
  • Kops ( Multi node kubernetes setup into AWS )
  • Kubeadm ( Multi Node Cluster in our own premises)

In this article we will install latest version of Kubernetes 1.7 on CentOS 7 / RHEL 7 with kubeadm utility. In my setup I am taking three CentOS 7 servers with minimal installation. One server will acts master node and rest two servers will be minion or worker nodes.

Kubernetes-settup-Diagram

On the Master Node following components will be installed

  • API Server  – It provides kubernetes API using Jason / Yaml over http, states of API objects are stored in etcd
  • Scheduler  – It is a program on master node which performs the scheduling tasks like launching containers in worker nodes based on resource availability
  • Controller Manager – Main Job of Controller manager is to monitor replication controllers and create pods to maintain desired state.
  • etcd – It is a Key value pair data base. It stores configuration data of cluster and cluster state.
  • Kubectl utility – It is a command line utility which connects to API Server on port 6443. It is used by administrators to create pods, services etc.

On Worker Nodes following components will be installed

  • Kubelet – It is an agent which runs on every worker node, it connects to docker  and takes care of creating, starting, deleting containers.
  • Kube-Proxy – It routes the traffic to appropriate containers based on ip address and port number of the incoming request. In other words we can say it is used for port translation.
  • Pod – Pod can be defined as a multi-tier or group of containers that are deployed on a single worker node or docker host.

Installations Steps of Kubernetes 1.7 on CentOS 7 / RHEL 7

Perform the following steps on Master Node

Step 1: Disable SELinux & setup firewall rules

Login to your kubernetes master node and set the hostname and disable selinux using following commands

~]# hostnamectl set-hostname 'k8s-master'
~]# exec bash
~]# setenforce 0
~]# sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/sysconfig/selinux

Set the following firewall rules.

[root@k8s-master ~]# firewall-cmd --permanent --add-port=6443/tcp
[root@k8s-master ~]# firewall-cmd --permanent --add-port=2379-2380/tcp
[root@k8s-master ~]# firewall-cmd --permanent --add-port=10250/tcp
[root@k8s-master ~]# firewall-cmd --permanent --add-port=10251/tcp
[root@k8s-master ~]# firewall-cmd --permanent --add-port=10252/tcp
[root@k8s-master ~]# firewall-cmd --permanent --add-port=10255/tcp
[root@k8s-master ~]# firewall-cmd --reload
[root@k8s-master ~]# echo '1' > /proc/sys/net/bridge/bridge-nf-call-iptables

Note: In case you don’t have your own dns server then update /etc/hosts file on master and worker nodes

192.168.1.30 k8s-master
192.168.1.40 worker-node1
192.168.1.50 worker-node2

Step 2: Configure Kubernetes Repository

Kubernetes packages are not available in the default CentOS 7 & RHEL 7 repositories, Use below command to configure its package repositories.

[root@k8s-master ~]# cat <<EOF > /etc/yum.repos.d/kubernetes.repo
> [kubernetes]
> name=Kubernetes
> baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-x86_64
> enabled=1
> gpgcheck=1
> repo_gpgcheck=1
> gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg
>         https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
> EOF [root@k8s-master ~]#

Step 3: Install Kubeadm and Docker

Once the package repositories are configured, run the beneath command to install kubeadm and docker packages.

[root@k8s-master ~]# yum install kubeadm docker -y

Start and enable kubectl and docker service

[root@k8s-master ~]# systemctl restart docker && systemctl enable docker
[root@k8s-master ~]# systemctl  restart kubelet && systemctl enable kubelet

Step 4: Initialize Kubernetes Master with ‘kubeadm init’

Run the beneath command to  initialize and setup kubernetes master.

[root@k8s-master ~]# kubeadm init

Output of above command would be something like below

kubeadm-init-output

As we can see in the output that kubernetes master has been initialized successfully. Execute the beneath commands to use the cluster as root user.

[root@k8s-master ~]# mkdir -p $HOME/.kube
[root@k8s-master ~]# cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
[root@k8s-master ~]# chown $(id -u):$(id -g) $HOME/.kube/config

Step 5: Deploy pod network to the cluster

Try to run below commands to get status of cluster and pods.

kubectl-get-nodes

To make the cluster status ready and kube-dns status running, deploy the pod network so that containers of different host communicated each other.  POD network is the overlay network between the worker nodes.

Run the beneath command to deploy network.

[root@k8s-master ~]# export kubever=$(kubectl version | base64 | tr -d '\n')
[root@k8s-master ~]# kubectl apply -f "https://cloud.weave.works/k8s/net?k8s-version=$kubever"
serviceaccount "weave-net" created
clusterrole "weave-net" created
clusterrolebinding "weave-net" created
daemonset "weave-net" created
[root@k8s-master ~]#

Now run the following commands to verify the status

[root@k8s-master ~]# kubectl get nodes
NAME         STATUS    AGE       VERSION
k8s-master   Ready     1h        v1.7.5
[root@k8s-master ~]# kubectl  get pods  --all-namespaces
NAMESPACE     NAME                                 READY     STATUS    RESTARTS   AGE
kube-system   etcd-k8s-master                      1/1       Running   0          57m
kube-system   kube-apiserver-k8s-master            1/1       Running   0          57m
kube-system   kube-controller-manager-k8s-master   1/1       Running   0          57m
kube-system   kube-dns-2425271678-044ww            3/3       Running   0          1h
kube-system   kube-proxy-9h259                     1/1       Running   0          1h
kube-system   kube-scheduler-k8s-master            1/1       Running   0          57m
kube-system   weave-net-hdjzd                      2/2       Running   0          7m
[root@k8s-master ~]#

Now let’s add worker nodes to the Kubernetes master nodes.

Perform the following steps on each worker node

Step 1: Disable SELinux & configure firewall rules on both the nodes

Before disabling SELinux set the hostname on the both nodes as ‘worker-node1’ and ‘worker-node2’ respectively

~]# setenforce 0
~]# sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/sysconfig/selinux
~]# firewall-cmd --permanent --add-port=10250/tcp
~]# firewall-cmd --permanent --add-port=10255/tcp
~]# firewall-cmd --permanent --add-port=30000-32767/tcp
~]# firewall-cmd --permanent --add-port=6783/tcp
~]# firewall-cmd  --reload
~]# echo '1' > /proc/sys/net/bridge/bridge-nf-call-iptables

Step 2: Configure Kubernetes Repositories on both worker nodes

~]# cat <<EOF > /etc/yum.repos.d/kubernetes.repo
> [kubernetes]
> name=Kubernetes
> baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-x86_64
> enabled=1
> gpgcheck=1
> repo_gpgcheck=1
> gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg
>         https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
> EOF

Step 3: Install kubeadm and docker package on both nodes

[root@worker-node1 ~]# yum  install kubeadm docker -y
[root@worker-node2 ~]# yum  install kubeadm docker -y

Start and enable docker service

[root@worker-node1 ~]# systemctl restart docker && systemctl enable docker
[root@worker-node2 ~]# systemctl restart docker && systemctl enable docker

Step 4: Now Join worker nodes to master node

To join worker nodes to Master node, a token is required. Whenever kubernetes master initialized , then in the output we get command and token.  Copy that command and run on both nodes.

[root@worker-node1 ~]# kubeadm join --token a3bd48.1bc42347c3b35851 192.168.1.30:6443

Output of above command would be something like below

kubeadm-node1

[root@worker-node2 ~]# kubeadm join --token a3bd48.1bc42347c3b35851 192.168.1.30:6443

Output would be something like below

kubeadm-join-node2

Now verify Nodes status from master node using kubectl command

[root@k8s-master ~]# kubectl get nodes
NAME           STATUS    AGE       VERSION
k8s-master     Ready     2h        v1.7.5
worker-node1   Ready     20m       v1.7.5
worker-node2   Ready     18m       v1.7.5
[root@k8s-master ~]#

As we can see master and worker nodes are in ready status. This concludes that kubernetes 1.7 has been installed successfully and also we have successfully joined two worker nodes.  Now we can create pods and services.

Installing Kubernetes on your Windows with Minikube

Personally I think if you are looking for a container management solution in today’s world, you have to invest your time in Kubernetes (k8s). There is no doubt about that because of multiple factors. To the best of my undestanding, these points include:

  • Kubernetes is Open Source
  • Great momentum in terms of activities & contribution at its Open Source Project
  • Decades of experience running its predecessor at Google
  • Support of multiple OS and infrastructure software vendors
  • Rate at which features are being released
  • Production readiness (Damn it, Pokemon Go met its scale due to Kubernetes)
  • Number of features available. Check out the list of features at the home page.

The general perception about a management solution like Kubernetes is that it would require quite a bit of setup for you to try it out locally. What this means is that it would take some time to set it up but more than setting it up, you might probably get access to it only during staging phase or something like that. Ideally you want a similar environment in your development too, so that you are as close to what it takes to run your application. The implications of this is that you want it running on your laptop/desktop, where you are likely to do your development.

This was the goal behind the minikube project and the team has put in fantastic effort to help us setup and run Kubernetes on our development machines. This is as simple and portable as it can get. The tagline of minikube project says it all: “Run Kubernetes locally”.

Side Note: The design of the minikube logo makes for interesting reading.

This post is going to take you through setting up Minikube on your Windows development machine and then taking it for a Hello World spin to see a local Kubernetes cluster in action. Along the way, I will highlight my environment and what I had to do to get the experimental build of minikube working on my Windows machine. Yes, it is experimental software, but it works!

If you are not on Windows, the instructions to setup minikube on either your Linux machine or Mac machine are also available here. Check it out. You can then safely skip over the setup and go to the section where we do a quick Hello World to test drive Kubernetes locally.

Keep in mind that Minikube gives you a single node cluster that is running in a VM on your development machine.

Of course, once you are done with what you see in this blog, I strongly recommend that you also look at Managed Container Orchestration solutions like Google Container Engine.

Let’s get started now with installation of minikube. But first, we must make sure that our development machine has some of the pre-requisites required to run it. Do not ignore that!

Using VirtualBox and not Hyper-V

VirtualBox and Hyperv (which is available on Windows 10) do not make a happy pair and you are bound to run into situations where the tools get confused. I preferred to use VirtualBox and avoid all esoteric command-line switches that we need to provide to enable creation of the underlying Docker hosts, etc.

To disable Hyper-V, go to Turn Windows features on or off and you will see a dialog with list of Windows features as shown below. Navigate to the Hyper-V section and disable it completely.

This will require a restart to the machine to take effect and on my machine, it even ended up doing a Windows Update, configuring it and a good 10 minutes later, it was back up.

Great! We have everything now to get going.

Development Machine Environment

I am assuming that you have a setup that is similar to this. I believe, you should be fine on Windows 7 too and it would not have the HyperV stuff, instructions of which I will give in a while.

  • Windows 10 Laptop. VT-x/AMD-v virtualization must be enabled in BIOS.
  • Docker Toolbox v1.12.0. The toolbox sets up VirtualBox and I have gone with that.
  • kubectl command line utility. This is the CLI utility for the Kubernetes cluster and you need to install it and have it available in your PATH. To install the latest 1.4 release, do the following: Go to the browser and give the following URL : http://storage.googleapis.com/kubernetes-release/release/v1.8.1/bin/windows/amd64/kubectl.exe. This will download the kubectl CLI executable. Please make it available in the environment PATH variable.

Note: kubectl versions are available at a generic location as per the following format: https://storage.googleapis.com/kubernetes-release/release/${K8S_VERSION}/bin/${GOOS}/${GOARCH}/${K8S_BINARY}

To find the latest kubectl version goto this link:  https://storage.googleapis.com/kubernetes-release/release/stable.txt

Minikube installation

The first step is to take the kubectl.exe file that you downloaded in the previous step and place that in the C:\ folder.

The next step is to download the minikube binary from the following location: https://github.com/kubernetes/minikube/releases

Go to the Windows download link as shown below:

This will start downloading the v0.22.3 release of the executable. The file name is minikube-windows-amd64.exe. Just rename this to minikube.exeand place it in C:\ drive, alongside the kubectl.exe file from the previous section.

You are all set now to launch a local Kubernetes one-node cluster!

All the steps moving forward are being done in Powershell. Launch Powershell in Administrative mode (Ctrl-Shift-Enter) and navigate to C:\ drive where the kubectl.exe and minikube.exe files are present.

A few things to note

Let’s do our standard testing to validate our utilities.

If you go to your %HOMEPATH%\.minikube folder now, you will notice that several folders got created. Take a look!

There are multiple commands that Minikube supports. You can use the standard ` — help` option to see the list of commands that it has:

PS C:\> .\minikube --help
Minikube is a CLI tool that provisions and manages single-node Kubernetes clusters optimized for development workflows
Usage:
  minikube [command]
Available Commands:
  dashboard        Opens/displays the kubernetes dashboard URL for your local cluster
  delete           Deletes a local kubernetes cluster.
  docker-env       sets up docker env variables; similar to '$(docker-machine env)'
  get-k8s-versions Gets the list of available kubernetes versions available for minikube.
  ip               Retrieve the IP address of the running cluster.
  logs             Gets the logs of the running localkube instance, used for debugging minikube, not user code.
  config           Modify minikube config
  service          Gets the kubernetes URL for the specified service in your local cluster
  ssh              Log into or run a command on a machine with SSH; similar to 'docker-machine ssh'
  start            Starts a local kubernetes cluster.
  status           Gets the status of a local kubernetes cluster.
  stop             Stops a running local kubernetes cluster.
  version          Print the version of minikube.
Flags:
      --alsologtostderr[=false]: log to standard error as well as files
      --log-flush-frequency=5s: Maximum number of seconds between log flushes
      --log_backtrace_at=:0: when logging hits line file:N, emit a stack trace
      --log_dir="": If non-empty, write log files in this directory
      --logtostderr[=false]: log to standard error instead of files
      --show-libmachine-logs[=false]: Whether or not to show logs from libmachine.
      --stderrthreshold=2: logs at or above this threshold go to stderr
      --v=0: log level for V logs
      --vmodule=: comma-separated list of pattern=N settings for file-filtered logging
Use "minikube [command] --help" for more information about a command.

I have highlighted a couple of Global flags that you can use in all the commands for minikube. These flags are useful to see what is going on inside the hood at times and also for seeing the output on the standard output (console/command).

Minikube supports multiple versions of Kubernetes and the latest version is v1.7.5. To check out the different versions supported try out the following command:

PS C:\> .\minikube get-k8s-versions
The following Kubernetes versions are available:
 - v1.7.5
 - v1.7.4
 - v1.7.3
 - v1.7.2
 - v1.7.0
 - v1.7.0-rc.1
 - v1.7.0-alpha.2
 - v1.6.4
 - v1.6.3
 - v1.6.0
 - v1.6.0-rc.1
 - v1.6.0-beta.4
 - v1.6.0-beta.3
 - v1.6.0-beta.2
 - v1.6.0-alpha.1
 - v1.6.0-alpha.0
 - v1.5.3
 - v1.5.2
 - v1.5.1
 - v1.4.5
 - v1.4.3
 - v1.4.2
 - v1.4.1
 - v1.4.0
 - v1.3.7
 - v1.3.6
 - v1.3.5
 - v1.3.4
 - v1.3.3
 - v1.3.0

Starting our Cluster

We are now ready to launch our Kubernetes cluster locally. We will use the start command for it.

Note: You might run into multiple issues while starting a cluster the first time. I have several of them and have created a section at the end of this blog post on Troubleshooting. Take a look at it, in case you run into any issues.

You can check out the help and description of the command/flags/options via the help option as shown below:

PS C:\> .\minikube.exe start --help

You will notice several Flags that you can provide to the start command and while there are some useful defaults, we are going to be a bit specific, so that we can better understand things.

We want to use Kubernetes v1.7.5 and while the VirtualBox driver is default on windows, we are going to be explicit about it. At the same time, we are going to use a couple of the Global Flags that we highlighted earlier, so that we can see what is going on under the hood.

All we need to do is give the following command (I have separated the flags on separate line for better readability). The output is also attached.

PS C:\> .\minikube.exe start --kubernetes-version="v1.7.5" 
                             --vm-driver="virtualbox" 
                             --alsologtostderr
W1004 13:01:30.429310    9296 root.go:127] Error reading config file at C:\Users\irani_r\.minikube\config\config.json: o
pen C:\Users\irani_r\.minikube\config\config.json: The system cannot find the file specified.
I1004 13:01:30.460582    9296 notify.go:103] Checking for updates...
Starting local Kubernetes cluster...
Creating CA: C:\Users\irani_r\.minikube\certs\ca.pem
Creating client certificate: C:\Users\irani_r\.minikube\certs\cert.pemRunning pre-create checks...
Creating machine...
(minikube) Downloading C:\Users\irani_r\.minikube\cache\boot2docker.iso from file://C:/Users/irani_r/.minikube/cache/iso
/minikube-0.7.iso...
(minikube) Creating VirtualBox VM...
(minikube) Creating SSH key...
(minikube) Starting the VM...
(minikube) Check network to re-create if needed...
(minikube) Waiting for an IP...
Waiting for machine to be running, this may take a few minutes...
Detecting operating system of created instance...
Waiting for SSH to be available...
Detecting the provisioner...
Provisioning with boot2docker...
Copying certs to the local machine directory...
Copying certs to the remote machine...
Setting Docker configuration on the remote daemon...
Checking connection to Docker...
Docker is up and running!
I1004 13:03:06.480550    9296 cluster.go:389] Setting up certificates for IP: %s 192.168.99.100
I1004 13:03:06.567686    9296 cluster.go:202] sudo killall localkube || true
I1004 13:03:06.611680    9296 cluster.go:204] killall: localkube: no process killed
I1004 13:03:06.611680    9296 cluster.go:202]
# Run with nohup so it stays up. Redirect logs to useful places.
sudo sh -c 'PATH=/usr/local/sbin:$PATH nohup /usr/local/bin/localkube   --generate-certs=false --logtostderr=true --node
-ip=192.168.99.100 > /var/lib/localkube/localkube.err 2> /var/lib/localkube/localkube.out < /dev/null & echo $! > /var/r
un/localkube.pid &'
I1004 13:03:06.658605    9296 cluster.go:204]
Kubectl is now configured to use the cluster.
PS C:\>

Let us understand what it is doing behind the scenes in brief. I have also highlighted some of the key lines in the output above:

  1. It generates the certificates and then proceeds to provision a local Docker host. This will result in a VM created inside of VirtualBox.
  2. That host is provisioned with the boot2Docker ISO image.
  3. It does its magic of setting it up, assigning it an IP and all the works.
  4. Finally, it prints out a message that kubectl is configured to talk to your local Kubernetes cluster.

You can now check on the status of the local cluster via the status command:

PS C:\> .\minikube.exe status
minikubeVM: Running
localkube: Running

You can also use the kubectl CLI to get the cluster information:

PS C:\> .\kubectl.exe cluster-info
Kubernetes master is running at https://192.168.99.100:8443
kubernetes-dashboard is running at https://192.168.99.100:8443/api/v1/proxy/namespaces/kube-system/services/kubernetes-d
ashboard
To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.

Kubernetes Client and Server version

Let us do a quick check of the Kubernetes version at the client and server level. Execute the following command:

PS C:\> .\kubectl version
Client Version: version.Info{Major:"1", Minor:"4", GitVersion:"v1.7.5", GitCommit:"a16c0a7f71a6f93c7e0f222d961f4675cd97a
46b", GitTreeState:"clean", BuildDate:"2016-09-26T18:16:57Z", GoVersion:"go1.6.3", Compiler:"gc", Platform:"windows/amd6
4"}
Server Version: version.Info{Major:"1", Minor:"4", GitVersion:"v1.7.5", GitCommit:"a16c0a7f71a6f93c7e0f222d961f4675cd97a
46b", GitTreeState:"dirty", BuildDate:"1970-01-01T00:00:00Z", GoVersion:"go1.7.1", Compiler:"gc", Platform:"linux/amd64"
}

You will notice that both client and server are at version 1.4.

Cluster IP Address

You can get the IP address of the cluster via the ip command:

PS C:\> .\minikube.exe ip
192.168.99.100

Kubernetes Dashboard

You can launch the Kubernetes Dashboard at any point via the dashboardcommand as shown below:

PS C:\> .\minikube.exe dashboard

This will automatically launch the Dashboard in your local browser. However if you just want to nab the Dashboard URL, you can use the following flag:

PS C:\> .\minikube.exe dashboard --url=true
http://192.168.99.100:30000

There is a great post on how the Kubernetes Dashboard underwent a design change in version 1.4. It explains how the information is split up into respective sections i.e. Workloads , Services and Discovery, Storage and Configuration, which are present on the left-side menu and via which you can sequentially introspect more details of your cluster. All of this is provided by a nifty filter for the Namespace value above.

If you look at the Kubernetes dashboard right now, you will see that it indicates that nothing has been deployed. Let us step back and think what we have so far. We have launched a single-node cluster .. right? Click on the Node link and you will see that information:

The above node information can also be obtained by using the kubectl CLI to get the list of nodes.

PS C:\> .\kubectl.exe get nodes
NAME       STATUS    AGE
minikube   Ready     51m

Hopefully, you are now able to relate how some of the CLI calls are reflected in the Dashboard too. Let’s move forward. But before that, one important tip!

Tip: use-context minikube

If you had noticed closely when we started the cluster, there is a statement in the output that says “Kubectl is now configured to use the cluster.” What this is supposed to do is to eventually set the current context for the kubectl utility so that it knows which cluster it is talking to. Behind the scenes in your %HOMEPATH%\.kube directory, there is a config file that contains information about your Kubernetes cluster and the details for connecting to your various clusters is present over there.

In short, we have to be sure that the kubectl is pointing to the right cluster. In our case, the cluster name is minikube.

In case you see an error like the one below (I got it a few times), then you need to probably set the context again.

PS C:\> kubectl get nodes
error: You must be logged in to the server (the server has asked for the client to provide credentials)

The command for that is:

PS C:\> kubectl config use-context minikube
switched to context "minikube".

Running a Workload

Let us proceed now to running a simple Nginx container to see the whole thing in action:

We are going to use the run command as shown below:

PS C:\> .\kubectl.exe run hello-nginx --image=nginx --port=80
deployment "hello-nginx" created

This creates a deployment and we can investigate into the Pod that gets created, which will run the container:

PS C:\> .\kubectl.exe get pods
NAME                   READY     STATUS              RESTARTS   AGE
hello-nginx-24710...   0/1       ContainerCreating   0          2m

You can see that the STATUS column value is ContainerCreating.

Now, let us go back to the Dashboard (I am assuming that you either have it running or can launch it again via the minikube dashboard command):

You can notice that if we go to the Deployments option, the Deployment is listed and the status is still in progress. You can also notice that the Pods value is 0/1.

If we wait for a while, the Pod will eventually get created and it will ready as the command below shows:

PS C:\> .\kubectl.exe get pods
NAME                   READY     STATUS    RESTARTS   AGE
hello-nginx-24710...   1/1       Running   0          3m

If we see the Dashboard again, the Deployment is ready now:

If we visit the Replica Sets now, we can see it:

Click on the Replica Set name and it will show the Pod details as given below:

Alternately, you can also get to the Pods via the Pods link in the Workloads as shown below:

Click on the Pod and you can get various details on it as given below:

You can see that it has been given some default labels. You can see its IP address. It is part of the node named minikube. And most importantly, there is a link for View Logs too.

The 1.4 dashboard greatly simplifies using Kubernetes and explaining it to everyone. It helps to see what is going on in the Dashboard and then the various commands in kubectl will start making sense more.

We could have got the Node and Pod details via a variety of kubectl describe node/pod commands and we can still do that. An example of that is shown below:

PS C:\> .\kubectl.exe describe pod hello-nginx-2471083592-4vfz8
Name:           hello-nginx-2471083592-4vfz8
Namespace:      default
Node:           minikube/192.168.99.100
Start Time:     Tue, 04 Oct 2016 14:05:15 +0530
Labels:         pod-template-hash=2471083592
                run=hello-nginx
Status:         Running
IP:             172.17.0.3
Controllers:    ReplicaSet/hello-nginx-2471083592
Containers:
  hello-nginx:
    Container ID:       docker://98a9e303f0dbf21db80a20aea744725c9bd64f6b2ce2764379151e3ae422fc18
    Image:              nginx
    Image ID:           docker://sha256:ba6bed934df2e644fdd34e9d324c80f3c615544ee9a93e4ce3cfddfcf84bdbc2
    Port:               80/TCP
    State:              Running
      Started:          Tue, 04 Oct 2016 14:06:02 +0530
    Ready:              True
    Restart Count:      0
    Volume Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-rie7t (ro)
    Environment Variables:      <none>
..... /// REST OF THE OUTPUT ////

Expose a Service

It is time now to expose our basic Nginx deployment as a service. We can use the command shown below:

PS C:\> .\kubectl.exe expose deployment hello-nginx --type=NodePort
service "hello-nginx" exposed

If we visit the Dashboard at this point and go to the Services section, we can see out hello-nginx service entry.

Alternately, we can use kubectl too, to check it out:

PS C:\> .\kubectl.exe get services
NAME          CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
hello-nginx   10.0.0.24    <nodes>       80/TCP    3m
kubernetes    10.0.0.1     <none>        443/TCP   1h
PS C:\> .\kubectl.exe describe service hello-nginx
Name:                   hello-nginx
Namespace:              default
Labels:                 run=hello-nginx
Selector:               run=hello-nginx
Type:                   NodePort
IP:                     10.0.0.24
Port:                   <unset> 80/TCP
NodePort:               <unset> 31155/TCP
Endpoints:              172.17.0.3:80
Session Affinity:       None
No events.

We can now use the minikube service to understand the URL for the service as shown below:

PS C:\> .\minikube.exe service --url=true hello-nginx
http://192.168.99.100:31155

Alternately, if we do not use the url flag, then it can directly launch the browser and hit the service endpoint:

PS C:\> .\minikube.exe service hello-nginx
Opening kubernetes service default/hello-nginx in default browser...

View Logs

Assuming that you have accessed the service once in the browser as shown above, let us look at an interesting thing now. Go to the Service link in the Dashboard.

Click on the hello-nginx service. This will also show the list of Pods (single) as shown below. Click on the icon for Logs as highlighted below:

This will show the logs for that particular Pod and with HTTP Request calls that was just made.

You could do the same by using the logs <podname> command for the kubectl CLI:

PS C:\> .\kubectl logs hello-nginx-2471083592-4vfz8
172.17.0.1 - - [04/Oct/2016:09:00:33 +0000] "GET / HTTP/1.1" 200 612 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Appl
eWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36" "-"
2016/10/04 09:00:33 [error] 5#5: *1 open() "/usr/share/nginx/html/favicon.ico" failed (2: No such file or directory), cl
ient: 172.17.0.1, server: localhost, request: "GET /favicon.ico HTTP/1.1", host: "192.168.99.100:31155", referrer: "http
://192.168.99.100:31155/"
172.17.0.1 - - [04/Oct/2016:09:00:33 +0000] "GET /favicon.ico HTTP/1.1" 404 571 "http://192.168.99.100:31155/" "Mozilla/
5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36" "-"
PS C:\>

Scaling the Service

OK, I am not yet done!

When we created the deployment, we did not mention about the number of instances for our service. So we just had one Pod that was provisioned on the single node.

Let us go and see how we can scale this via the scale command. We want to scale it to 3 Pods.

PS C:\> .\kubectl scale --replicas=3 deployment/hello-nginx
deployment "hello-nginx" scaled

We can see the status of the deployment in a while:

PS C:\> .\kubectl.exe get deployment
NAME          DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
hello-nginx   3         3         3            3           1h

Now, if we visit the Dashboard for our Deployment:

We have the 3/3 Pods available. Similarly, we can see our Service or Pods.

or the Pod list:

Stopping and Deleting the Cluster

This is straightforward. You can use the stop and delete commands for minikube utility.

Limitations

Minikube is a work in progress at this moment and it does not support all the features of Kubernetes. Please refer to the minikube documentation, where it clearly states what is currently supported.

Troubleshooting Issues on Windows 10

My experience to get the experimental build of minikube working on Windows was not exactly a smooth one, but that is to be expected from anything that calls itself experimental.

I faced several issues and hope that it will save some time for you. I do not have the time to investigate deeper into why some of the stuff worked for me since my focus is to get it up and running on Windows. So if you have some specific comments around that, that will be great and I can add to this blog post.

In no order of preference, here you go:

Use Powershell

I used Powershell and not command line. Ensure that Powershell is launched in Administrative mode. This means Ctrl + Shift + Enter.

Put minikube.exe file in C:\ drive

I saw some issues that mentioned to do that. I did not experiment too much and went with C:\ drive.

Clear up .minikube directory

If there were some issues starting up minikube first time and then you try to start it again, you might see errors that say stuff like “Starting Machine” or “Machine exists” and then a bunch of errors before it gives up. I suggest that you clear up the .minikube directory that is present in %HOMEPATH%\.minikube directory. In my case, it is C:\Users\irani_r\.minikube. You will see a bunch of folders there. Just delete them all and start all over again.

To see detailed error logging, give the following flags while starting up the cluster:

--show-libmachine-logs --alsologtostderr

Example of the error trace for me was as follows:

PS C:\> .\minikube start --show-libmachine-logs --alsologtostderr
W1003 15:59:52.796394   12080 root.go:127] Error reading config file at C:\Users\irani_r\.minikube\config\config.json: o
pen C:\Users\irani_r\.minikube\config\config.json: The system cannot find the file specified.
I1003 15:59:52.800397   12080 notify.go:103] Checking for updates...
Starting local Kubernetes cluster...
I1003 15:59:53.164759   12080 cluster.go:75] Machine exists!
I1003 15:59:54.133728   12080 cluster.go:82] Machine state:  Error
E1003 15:59:54.133728   12080 start.go:85] Error starting host: Error getting state for host: machine does not exist. Re
trying.
I1003 15:59:54.243132   12080 cluster.go:75] Machine exists!
I1003 15:59:54.555738   12080 cluster.go:82] Machine state:  Error
E1003 15:59:54.555738   12080 start.go:85] Error starting host: Error getting state for host: machine does not exist. Re
trying.
I1003 15:59:54.555738   12080 cluster.go:75] Machine exists!
I1003 15:59:54.790128   12080 cluster.go:82] Machine state:  Error
E1003 15:59:54.790128   12080 start.go:85] Error starting host: Error getting state for host: machine does not exist. Re
trying.
E1003 15:59:54.790128   12080 start.go:91] Error starting host:  Error getting state for host: machine does not exist
Error getting state for host: machine does not exist
Error getting state for host: machine does not exist

Disable Hyper-V

As earlier mentioned, VirtualBox and Hyper-V are not the happiest of co-workers. Definitely disable one of them on your machine. As per the documentation of minikube, both virtualbox and hyperv drivers are supported on Windows. I will do a test of Hyper-V someday but I went with disabling Hyper-V and used VirtualBox only. The steps to disable Hyper-V correctly were shown earlier in this blog post.

 

Install KVM Hypervisor on CentOS 7.x and RHEL 7.x

KVM is an open source hardware virtualization software through which we can create and run multiple Linux based and windows based virtual machines simultaneously. KVM is known as Kernel based Virtual Machine because when we install KVM package then KVM module is loaded into the current kernel and turns our Linux machine into a hypervisor.

In this post first we will demonstrate how we can install KVM hypervisor on CentOS 7.x and RHEL 7.x and then we will try to install virtual machines.

Before proceeding KVM installation, let’s check whether your system’s CPU supports Hardware Virtualization.

Run the beneath command from the console.

[root@linuxtechi ~]# grep -E '(vmx|svm)' /proc/cpuinfo

We should get the word either vmx or svm in the output, otherwise CPU doesn’t support virtualization.

Step:1 Install KVM and its associate packages

Run the following yum command to install KVM and its associated packages.

[root@linuxtechi ~]# yum install qemu-kvm qemu-img virt-manager libvirt libvirt-python libvirt-client virt-install virt-viewer bridge-utils

Start and enable the libvirtd service

[root@linuxtechi ~]# systemctl start libvirtd
[root@linuxtechi ~]# systemctl enable libvirtd

Run the beneath command to check whether KVM module is loaded or not

[root@linuxtechi ~]# lsmod | grep kvm
kvm_intel             162153  0
kvm                   525409  1 kvm_intel
[root@linuxtechi ~]#

Ansible cheat sheet

Configuration file

intro_configuration.html

First one found from of

  • Contents of $ANSIBLE_CONFIG
  • ./ansible.cfg
  • ~/.ansible.cfg
  • /etc/ansible/ansible.cfg

Configuration settings can be overridden by environment variables – see constants.py in the source tree for names.

Patterns

intro_patterns.html

Used on the ansible command line, or in playbooks.

  • all (or *)
  • hostname: foo.example.com
  • groupname: webservers
  • or: webservers:dbserver
  • exclude: webserver:!phoenix
  • intersection: webservers:&staging

Operators can be chained: webservers:dbservers:&staging:!phoenix

Patterns can include variable substitutions: {{foo}}, wildcards: *.example.com or 192.168.1.*, and regular expressions: ~(web|db).*\.example\.com

Inventory files

intro_inventory.htmlintro_dynamic_inventory.html

‘INI-file’ structure, blocks define groups. Hosts allowed in more than one group. Non-standard SSH port can follow hostname separated by ‘:’ (but see also ansible_ssh_port below).

Hostname ranges: www[01:50].example.comdb-[a:f].example.com

Per-host variables: foo.example.com foo=bar baz=wibble

  • [foo:children]: new group foo containing all members if included groups
  • [foo:vars]: variable definitions for all members of group foo

Inventory file defaults to /etc/ansible/hosts. Veritable with -i or in the configuration file. The ‘file’ can also be a dynamic inventory script. If a directory, all contained files are processed.

Variable files:

intro_inventory.html

YAML; given inventory file at ./hosts:

  • ./group_vars/foo: variable definitions for all members of group foo
  • ./host_vars/foo.example.com: variable definitions for foo.example.com

group_vars and host_vars directories can also exist in the playbook directory. If both paths exist, variables in the playbook directory will be loaded second.

Behavioral inventory parameters:

intro_inventory.html

  • ansible_ssh_host
  • ansible_ssh_port
  • ansible_ssh_user
  • ansible_ssh_pass
  • ansible_sudo_pass
  • ansible_connection
  • ansible_ssh_private_key_file
  • ansible_python_interpreter
  • ansible_*_interpreter

Playbooks

playbooks_intro.htmlplaybooks_roles.html

Playbooks are a YAML list of one or more plays. Most (all?) keys are optional. Lines can be broken on space with continuation lines indented.

Playbooks consist of a list of one or more ‘plays’ and/or inclusions:

---
- include: playbook.yml
- <play>
- ...

Plays

playbooks_intro.htmlplaybooks_roles.htmlplaybooks_variables.htmlplaybooks_conditionals.html,playbooks_acceleration.htmlplaybooks_delegation.htmlplaybooks_prompts.htmlplaybooks_tags.html Forum postingForum postinb

Plays consist of play metadata and a sequence of task and handler definitions, and roles.

- hosts: webservers
  remote_user: root
  sudo: yes
  sudo_user: postgress
  su: yes
  su_user: exim
  gather_facts: no
  accelerate: no
  accelerate_port: 5099
  any_errors_fatal: yes
  max_fail_percentage: 30
  connection: local
  serial: 5
  vars:
    http_port: 80
  vars_files:
    - "vars.yml"
    - [ "try-first.yml", "try-second-.yml" ]
  vars_prompt:
    - name: "my_password2"
      prompt: "Enter password2"
      default: "secret"
      private: yes
      encrypt: "md5_crypt"
      confirm: yes
      salt: 1234
      salt_size: 8
  tags: 
    - stuff
    - nonsence
  pre_tasks:
    - <task>
    - ...
  roles:
    - common
    - { role: common, port: 5000, when: "bar == 'Baz'", tags :[one, two] }
    - { role: common, when: month == 'Jan' }
    - ...
  tasks:
    - include: tasks.yaml
    - include: tasks.yaml foo=bar baz=wibble
    - include: tasks.yaml
      vars:
        foo: aaa 
        baz:
          - z
          - y
    - { include: tasks.yaml, foo: zzz, baz: [a,b]}
    - include: tasks.yaml
      when: day == 'Thursday'
    - <task>
    - ...
  post_tasks:
    - <task>
    - ...
  handlers:
    - include: handlers.yml
    - <task>
    - ...

Using encrypt with vars_prompt requires that Passlib is installed.

In addition the source code implies the availability of the following which don’t seem to be mentioned in the documentation: nameuser (deprecated), portaccelerate_ipv6role_names, and vault_password.

Task definitions

playbooks_intro.htmlplaybooks_roles.htmlplaybooks_async.htmlplaybooks_checkmode.htmlplaybooks_delegation.html,playbooks_environment.htmlplaybooks_error_handling.htmlplaybooks_tags.html ansible-1-5-released Forum postingAnsible examples

Each task definition is a list of items, normally including at least a name and a module invocation:

- name: task
  remote_user: apache
  sudo: yes
  sudo_user: postgress
  sudo_pass: wibble
  su: yes
  su_user: exim
  ignore_errors: True
  delegate_to: 127.0.0.1
  async: 45
  poll: 5
  always_run: no
  run_once: false
  meta: flush_handlers
  no_log: true
  environment: <hash>
  environment:
    var1: val1
    var2: val2
  tags: 
    - stuff
    - nonsence
  <module>: src=template.j2 dest=/etc/foo.conf
  action: <module>, src=template.j2 dest=/etc/foo.conf
  action: <module>
  args:
      src=template.j2
      dest=/etc/foo.conf
  local_action: <module> /usr/bin/take_out_of_pool {{ inventory_hostname }}
  when: ansible_os_family == "Debian"
  register: result
  failed_when: "'FAILED' in result.stderr"
  changed_when: result.rc != 2
  notify:
    - restart apache

delegate_to: 127.0.0.1 is implied by local_action:

The forms <module>: <args>action: <module> <args>, and local_action: <module> <args> are mutually-exclusive.

Additional keys when_*untilretries and delay are documented below under ‘Loops’.

In addition the source code implies the availability of the following which don’t seem to be mentioned in the documentation:first_available_file (deprecated), transportconnectionany_errors_fatal.

Roles

playbooks_roles.html

Directory structure:

playbook.yml
roles/
   common/
     tasks/
       main.yml
     handlers/
       main.yml
     vars/
       main.yml
     meta/
       main.yml
     defaults/
       main.yml
     files/
     templates/
     library/

Modules

modules.htmmodules_by_category.html

List all installed modules with

ansible-doc --list

Document a particular module with

ansible-doc <module>

Show playbook snippet for specified module

ansible-doc -i <module>

Variables

playbooks_roles.htmlplaybooks_variables.html

Names: letters, digits, underscores; starting with a letter.

Substitution examples:

  • {{ var }}
  • {{ var["key1"]["key2"]}}
  • {{ var.key1.key2 }}
  • {{ list[0] }}

YAML requires an item starting with a variable substitution to be quoted.

Sources:

  • Highest priority:
    • --extra-vars on the command line
  • General:
    • vars component of a playbook
    • From files referenced by vars_file in a playbook
    • From included files (incl. roles)
    • Parameters passed to includes
    • register: in tasks
  • Lower priority:
    • Inventory (set on host or group)
  • Lower priority:
    • Facts (see below)
    • Any /etc/ansible/facts.d/filename.fact on managed machines (sets variables with `ansible_local.filename. prefix)
  • Lowest priority
    • Role defaults (from defaults/main.yml)

Built-in:

  • hostvars (e.g. hostvars[other.example.com][...])
  • group_names (groups containing current host)
  • groups (all groups and hosts in the inventory)
  • inventory_hostname (current host as in inventory)
  • inventory_hostname_short (first component of inventory_hostname)
  • play_hosts (hostnames in scope for current play)
  • inventory_dir (location of the inventory)
  • inventoty_file (name of the inventory)

Facts:

Run ansible hostname -m setup, but in particular:

  • ansible_distribution
  • ansible_distribution_release
  • ansible_distribution_version
  • ansible_fqdn
  • ansible_hostname
  • ansible_os_family
  • ansible_pkg_mgr
  • ansible_default_ipv4.address
  • ansible_default_ipv6.address

Content of ‘registered’ variables:

playbooks_conditionals.htmlplaybooks_loops.html

Depends on module. Typically includes:

  • .rc
  • .stdout
  • .stdout_lines
  • .changed
  • .msg (following failure)
  • .results (when used in a loop)

See also failedchanged, etc filters.

When used in a loop the result element is a list containing all responses from the module.

Additionally available in templates:

  • ansible_managed: string containing the information below
  • template_host: node name of the templateâ��s machine
  • template_uid: the owner
  • template_path: absolute path of the template
  • template_fullpath: the absolute path of the template
  • template_run_date: the date that the template was rendered

Filters

playbooks_variables.html

  • {{ var | to_nice_json }}
  • {{ var | to_json }}
  • {{ var | from_json }}
  • {{ var | to_nice_yml }}
  • {{ var | to_yml }}
  • {{ var | from_yml }}
  • {{ result | failed }}
  • {{ result | changed }}
  • {{ result | success }}
  • {{ result | skipped }}
  • {{ var | manditory }}
  • {{ var | default(5) }}
  • {{ list1 | unique }}
  • {{ list1 | union(list2) }}
  • {{ list1 | intersect(list2) }}
  • {{ list1 | difference(list2) }}
  • {{ list1 | symmetric_difference(list2) }}
  • {{ ver1 | version_compare(ver2, operator='>=', strict=True }}
  • {{ list | random }}
  • {{ number | random }}
  • {{ number | random(start=1, step=10) }}
  • {{ list | join(" ") }}
  • {{ path | basename }}
  • {{ path | dirname }}
  • {{ path | expanduser }}
  • {{ path | realpath }}
  • {{ var | b64decode }}
  • {{ var | b64encode }}
  • {{ filename | md5 }}
  • {{ var | bool }}
  • {{ var | int }}
  • {{ var | quote }}
  • {{ var | md5 }}
  • {{ var | fileglob }}
  • {{ var | match }}
  • {{ var | search }}
  • {{ var | regex }}
  • {{ var | regexp_replace('from', 'to' )}}

See also default jinja2 filters. In YAML, values starting { must be quoted.

Lookups

playbooks_lookups.html

Lookups are evaluated on the control machine.

  • {{ lookup('file', '/etc/foo.txt') }}
  • {{ lookup('password', '/tmp/passwordfile length=20 chars=ascii_letters,digits') }}
  • {{ lookup('env','HOME') }}
  • {{ lookup('pipe','date') }}
  • {{ lookup('redis_kv', 'redis://localhost:6379,somekey') }}
  • {{ lookup('dnstxt', 'example.com') }}
  • {{ lookup('template', './some_template.j2') }}

Lookups can be assigned to variables and will be evaluated each time the variable is used.

Lookup plugins also support loop iteration (see below).

Conditions

playbooks_conditionals.html

when: <condition>, where condition is:

  • var == "Vaue"var >= 5, etc.
  • var, where var coreces to boolean (yes, true, True, TRUE)
  • var is definedvar is not defined
  • <condition1> and <condition2> (also or?)

Combined with with_items, the when statement is processed for each item.

when can also be applied to includes and roles. Conditional Imports and variable substitution in file and template names can avoid the need for explicit conditionals.

Loops

playbooks_loops.html

In addition the source code implies the availability of the following which don’t seem to be mentioned in the documentation: csvfileetcdinventory_hostname.

Standard:

- user: name={{ item }} state=present groups=wheel
  with_items:
    - testuser1
    - testuser2
   
- name: add several users
  user: name={{ item.name }} state=present groups={{ item.groups }}
  with_items:
    - { name: 'testuser1', groups: 'wheel' }
    - { name: 'testuser2', groups: 'root' }

  with_items: somelist

Nested:

- mysql_user: name={{ item[0] }} priv={{ item[1] }}.*:ALL                
                           append_privs=yes password=foo
  with_nested:
    - [ 'alice', 'bob', 'eve' ]
    - [ 'clientdb', 'employeedb', 'providerdb' ]

Over hashes:

Given

---
users:
  alice:
    name: Alice Appleworth
    telephone: 123-456-7890
  bob:
    name: Bob Bananarama
    telephone: 987-654-3210
    
tasks:
  - name: Print phone records
    debug: msg="User {{ item.key }} is {{ item.value.name }} 
                     ({{ item.value.telephone }})"
    with_dict: users

Fileglob:

- copy: src={{ item }} dest=/etc/fooapp/ owner=root mode=600
  with_fileglob:
    - /playbooks/files/fooapp/*

In a role, relative paths resolve relative to the roles/<rolename>/files directory.

With content of file:

(see example for authorized_key module)

- authorized_key: user=deploy key="{{ item }}"
  with_file:
    - public_keys/doe-jane
    - public_keys/doe-john

See also the file lookup when the content of a file is needed.

Parallel sets of data:

Given

---
alpha: [ 'a', 'b', 'c', 'd' ]
numbers:  [ 1, 2, 3, 4 ]

- debug: msg="{{ item.0 }} and {{ item.1 }}"
  with_together:
    - alpha
    - numbers

Subelements:

Given

---
users:
  - name: alice
    authorized:
      - /tmp/alice/onekey.pub
      - /tmp/alice/twokey.pub
  - name: bob
    authorized:
      - /tmp/bob/id_rsa.pub

- authorized_key: "user={{ item.0.name }} 
                   key='{{ lookup('file', item.1) }}'"
  with_subelements:
     - users
     - authorized

Integer sequence:

Decimal, hexadecimal (0x3f8) or octal (0600)

- user: name={{ item }} state=present groups=evens
  with_sequence: start=0 end=32 format=testuser%02x
      
  with_sequence: start=4 end=16 stride=2
      
  with_sequence: count=4

Random choice:

- debug: msg={{ item }}
  with_random_choice:
     - "go through the door"
     - "drink from the goblet"
     - "press the red button"
     - "do nothing"

Do-Until:

- action: shell /usr/bin/foo
  register: result
  until: result.stdout.find("all systems go") != -1
  retries: 5
  delay: 10

Results of a local program:

- name: Example of looping over a command result
  shell: /usr/bin/frobnicate {{ item }}
  with_lines: /usr/bin/frobnications_per_host 
                       --param {{ inventory_hostname }}

To loop over the results of a remote program, use register: result and then with_items: result.stdout_lines in a subsequent task.

Indexed list:

- name: indexed loop demo
  debug: msg="at array position {{ item.0 }} there is 
                                     a value {{ item.1 }}"
  with_indexed_items: some_list

Flattened list:

---
# file: roles/foo/vars/main.yml
packages_base:
  - [ 'foo-package', 'bar-package' ]
packages_apps:
  - [ ['one-package', 'two-package' ]]
  - [ ['red-package'], ['blue-package']]
  
- name: flattened loop demo
  yum: name={{ item }} state=installed
  with_flattened:
    - packages_base
    - packages_apps      

First found:

- name: template a file
  template: src={{ item }} dest=/etc/myapp/foo.conf
  with_first_found:
    - files:
        - {{ ansible_distribution }}.conf
        - default.conf
      paths:
         - search_location_one/somedir/
         - /opt/other_location/somedir/

Tags

Both plays and tasks support a tags: attribute.

- template: src=templates/src.j2 dest=/etc/foo.conf
  tags:
    - configuration

Tags can be applied to roles and includes (effectively tagging all included tasks)

roles:
    - { role: webserver, port: 5000, tags: [ 'web', 'foo' ] }

- include: foo.yml tags=web,foo

To select by tag:

ansible-playbook example.yml --tags "configuration,packages"
ansible-playbook example.yml --skip-tags "notification"

Command lines

ansible

Usage: ansible <host-pattern> [options]

Options:
  -a MODULE_ARGS, --args=MODULE_ARGS
                        module arguments
  -k, --ask-pass        ask for SSH password
  --ask-su-pass         ask for su password
  -K, --ask-sudo-pass   ask for sudo password
  --ask-vault-pass      ask for vault password
  -B SECONDS, --background=SECONDS
                        run asynchronously, failing after X seconds
                        (default=N/A)
  -C, --check           don't make any changes; instead, try to predict some
                        of the changes that may occur
  -c CONNECTION, --connection=CONNECTION
                        connection type to use (default=smart)
  -f FORKS, --forks=FORKS
                        specify number of parallel processes to use
                        (default=5)
  -h, --help            show this help message and exit
  -i INVENTORY, --inventory-file=INVENTORY
                        specify inventory host file
                        (default=/etc/ansible/hosts)
  -l SUBSET, --limit=SUBSET
                        further limit selected hosts to an additional pattern
  --list-hosts          outputs a list of matching hosts; does not execute
                        anything else
  -m MODULE_NAME, --module-name=MODULE_NAME
                        module name to execute (default=command)
  -M MODULE_PATH, --module-path=MODULE_PATH
                        specify path(s) to module library
                        (default=/usr/share/ansible)
  -o, --one-line        condense output
  -P POLL_INTERVAL, --poll=POLL_INTERVAL
                        set the poll interval if using -B (default=15)
  --private-key=PRIVATE_KEY_FILE
                        use this file to authenticate the connection
  -S, --su              run operations with su
  -R SU_USER, --su-user=SU_USER
                        run operations with su as this user (default=root)
  -s, --sudo            run operations with sudo (nopasswd)
  -U SUDO_USER, --sudo-user=SUDO_USER
                        desired sudo user (default=root)
  -T TIMEOUT, --timeout=TIMEOUT
                        override the SSH timeout in seconds (default=10)
  -t TREE, --tree=TREE  log output to this directory
  -u REMOTE_USER, --user=REMOTE_USER
                        connect as this user (default=jw35)
  --vault-password-file=VAULT_PASSWORD_FILE
                        vault password file
  -v, --verbose         verbose mode (-vvv for more, -vvvv to enable
                        connection debugging)
  --version             show program's version number and exit

ansible-playbook

Usage: ansible-playbook playbook.yml

Options:
  -k, --ask-pass        ask for SSH password
  --ask-su-pass         ask for su password
  -K, --ask-sudo-pass   ask for sudo password
  --ask-vault-pass      ask for vault password
  -C, --check           don't make any changes; instead, try to predict some
                        of the changes that may occur
  -c CONNECTION, --connection=CONNECTION
                        connection type to use (default=smart)
  -D, --diff            when changing (small) files and templates, show the
                        differences in those files; works great with --check
  -e EXTRA_VARS, --extra-vars=EXTRA_VARS
                        set additional variables as key=value or YAML/JSON
  -f FORKS, --forks=FORKS
                        specify number of parallel processes to use
                        (default=5)
  -h, --help            show this help message and exit
  -i INVENTORY, --inventory-file=INVENTORY
                        specify inventory host file
                        (default=/etc/ansible/hosts)
  -l SUBSET, --limit=SUBSET
                        further limit selected hosts to an additional pattern
  --list-hosts          outputs a list of matching hosts; does not execute
                        anything else
  --list-tasks          list all tasks that would be executed
  -M MODULE_PATH, --module-path=MODULE_PATH
                        specify path(s) to module library
                        (default=/usr/share/ansible)
  --private-key=PRIVATE_KEY_FILE
                        use this file to authenticate the connection
  --skip-tags=SKIP_TAGS
                        only run plays and tasks whose tags do not match these
                        values
  --start-at-task=START_AT
                        start the playbook at the task matching this name
  --step                one-step-at-a-time: confirm each task before running
  -S, --su              run operations with su
  -R SU_USER, --su-user=SU_USER
                        run operations with su as this user (default=root)
  -s, --sudo            run operations with sudo (nopasswd)
  -U SUDO_USER, --sudo-user=SUDO_USER
                        desired sudo user (default=root)
  --syntax-check        perform a syntax check on the playbook, but do not
                        execute it
  -t TAGS, --tags=TAGS  only run plays and tasks tagged with these values
  -T TIMEOUT, --timeout=TIMEOUT
                        override the SSH timeout in seconds (default=10)
  -u REMOTE_USER, --user=REMOTE_USER
                        connect as this user (default=jw35)
  --vault-password-file=VAULT_PASSWORD_FILE
                        vault password file
  -v, --verbose         verbose mode (-vvv for more, -vvvv to enable
                        connection debugging)
  --version             show program's version number and exit

ansible-vault

playbooks_vault.html

Usage: ansible-vault [create|decrypt|edit|encrypt|rekey] [--help] [options] file_name

Options:
  -h, --help  show this help message and exit

See 'ansible-vault <command> --help' for more information on a specific command.

ansible-doc

Usage: ansible-doc [options] [module...]

Show Ansible module documentation

Options:
  --version             show program's version number and exit
  -h, --help            show this help message and exit
  -M MODULE_PATH, --module-path=MODULE_PATH
                             Ansible modules/ directory
  -l, --list            List available modules
  -s, --snippet         Show playbook snippet for specified module(s)
  -v                    Show version number and exit

ansible-galaxy

Usage: ansible-galaxy [init|info|install|list|remove] [--help] [options] ...

Options:
  -h, --help  show this help message and exit

  See 'ansible-galaxy <command> --help' for more information on a
  specific command 

ansible-pull

Usage: ansible-pull [options] [playbook.yml]

Useful ansible stuff

inventory_hostname

inventory_hostname‘ contains the name of the current node being worked on…. (as in, what it is defined in your hosts file as) so if you want to skip a task for a single node –

- name: Restart amavis
  service: name=amavis state=restarted
  when: inventory_hostname != "boris"

(Don’t restart Amavis for boris,  do for all others).

You could also use :

...
  when: inventory_hostname not in groups['group_name']
...

if your aim was to (perhaps skip) a task for some nodes in the specified group.

 

Need to check whether you need to reboot for a kernel update?

  1. If /vmlinuz doesn’t resolve to the same kernel as we’re running
  2. Reboot
  3. Wait 45 seconds before carrying on…
- name: Check for reboot hint.
  shell: if [ $(readlink -f /vmlinuz) != /boot/vmlinuz-$(uname -r) ]; then echo 'reboot'; else echo 'no'; fi
  ignore_errors: true
  register: reboot_hint

- name: Rebooting ...
  command: shutdown -r now "Ansible kernel update applied"
  async: 0
  poll: 0
  ignore_errors: true
  when: kernelup|changed or reboot_hint.stdout.find("reboot") != -1
  register: rebooting

- name: Wait for thing to reboot...
  pause: seconds=45
  when: rebooting|changed

Fixing ~/.ssh/known_hosts

Often an ansible script may create a remote node – and often it’ll have the same IP/name as a previous entity. This confuses SSH — so after creating :

- name: Fix .ssh/known_hosts. (1)
  local_action: command  ssh-keygen -f "~/.ssh/known_hosts" -R hostname

If you’re using ec2, for instance, you could do something like :

- name: Fix .ssh/known_hosts.
  local_action: command  ssh-keygen -f "~/.ssh/known_hosts" -R {{ item.public_ip }} 
  with_items: ec2_info.instances

Where ec2_info is your registered variable from calling the ‘ec2’ module.

Debug/Dump a variable?

- name: What's in reboot_hint?
  debug: var=reboot_hint

which might output something like :

"reboot_hint": {
        "changed": true, 
        "cmd": "if [ $(readlink -f /vmlinuz) != /boot/vmlinuz-$(uname -r) ]; then echo 'reboot'; else echo 'no'; fi", 
        "delta": "0:00:00.024759", 
        "end": "2014-07-29 09:05:06.564505", 
        "invocation": {
            "module_args": "if [ $(readlink -f /vmlinuz) != /boot/vmlinuz-$(uname -r) ]; then echo 'reboot'; else echo 'no'; fi", 
            "module_name": "shell"
        }, 
        "rc": 0, 
        "start": "2014-07-29 09:05:06.539746", 
        "stderr": "", 
        "stdout": "reboot", 
        "stdout_lines": [
            "reboot"
        ]
    }

Which leads on to —

Want to run a shell command do something with the output?

Registered variables have useful attributes like :

  • changed – set to boolean true if something happened (useful to tell when a task has done something on a remote machine).
  • stderr – contains stringy output from stderr
  • stdout – contains stringy output from stdout
  • stdout_lines – contains a list of lines (i.e. stdout split on \n).

(see above)

- name: Do something
  shell: /usr/bin/something | grep -c foo || true
  register: shell_output

So – we could :

- name: Catch some fish (there are at least 5)
  shell: /usr/bin/somethingelse 
  when: shell_output.stdout > "5"

Default values for a Variable, and host specific values.

Perhaps you’ll override a variable, or perhaps not … so you can do something like the following in a template :

...
max_allowed_packet = {{ mysql_max_allowed_packet|default('128M') }}
...

And for the annoying hosts that need a larger mysql_max_allowed_packet, just define it within the inventory hosts file like :

[linux_servers]
beech
busy-web-server mysql_max_allowed_packet=256M