100% found this document useful (2 votes)
9 views

(Ebook) Kubernetes Programming with Go: Programming Kubernetes Clients and Operators Using Go and the Kubernetes API by Philippe Martin ISBN 9781484290262, 1484290267 - Download the ebook today and own the complete version

The document provides information about various eBooks related to Kubernetes programming, including titles, authors, and links for instant downloads. It highlights the book 'Kubernetes Programming with Go' by Philippe Martin, which aims to teach readers how to program with the Kubernetes API using Go. The document also outlines the book's structure, including chapters that cover the Kubernetes API, Client-go library, Custom Resources, and Operators.

Uploaded by

kchylarock67
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
100% found this document useful (2 votes)
9 views

(Ebook) Kubernetes Programming with Go: Programming Kubernetes Clients and Operators Using Go and the Kubernetes API by Philippe Martin ISBN 9781484290262, 1484290267 - Download the ebook today and own the complete version

The document provides information about various eBooks related to Kubernetes programming, including titles, authors, and links for instant downloads. It highlights the book 'Kubernetes Programming with Go' by Philippe Martin, which aims to teach readers how to program with the Kubernetes API using Go. The document also outlines the book's structure, including chapters that cover the Kubernetes API, Client-go library, Custom Resources, and Operators.

Uploaded by

kchylarock67
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 71

Instant Ebook Access, One Click Away – Begin at ebooknice.

com

(Ebook) Kubernetes Programming with Go:


Programming Kubernetes Clients and Operators Using
Go and the Kubernetes API by Philippe Martin ISBN
9781484290262, 1484290267

https://ebooknice.com/product/kubernetes-programming-with-
go-programming-kubernetes-clients-and-operators-using-go-
and-the-kubernetes-api-47556106

OR CLICK BUTTON

DOWLOAD EBOOK

Get Instant Ebook Downloads – Browse at https://ebooknice.com


Instant digital products (PDF, ePub, MOBI) ready for you
Download now and discover formats that fit your needs...

Start reading on any device today!

(Ebook) Kubernetes Programming with Go: Programming Kubernetes Clients and Operators
Using Go and the Kubernetes API by Philippe Martin ISBN 9781484290255, 1484290259

https://ebooknice.com/product/kubernetes-programming-with-go-programming-
kubernetes-clients-and-operators-using-go-and-the-kubernetes-api-47434838

ebooknice.com

(Ebook) Kubernetes Operators by Jason Dobies and Joshua Wood

https://ebooknice.com/product/kubernetes-operators-49849748

ebooknice.com

(Ebook) Kubernetes: Preparing for the CKA and CKAD Certifications by Martin,
Philippe ISBN 9781484264942, 1484264940

https://ebooknice.com/product/kubernetes-preparing-for-the-cka-and-ckad-
certifications-29874148

ebooknice.com

(Ebook) gRPC: Up and Running: Building Cloud Native Applications with Go and Java
for Docker and Kubernetes by Kasun Indrasiri, Danesh Kuruppu ISBN 9781492058335,
1492058335, B0845YMM37

https://ebooknice.com/product/grpc-up-and-running-building-cloud-native-
applications-with-go-and-java-for-docker-and-kubernetes-10690006

ebooknice.com
(Ebook) Go Systems Programming: Master Linux and Unix system level programming with
Go by Mihalis Tsoukalos ISBN 9781787125643, 1787125645

https://ebooknice.com/product/go-systems-programming-master-linux-and-unix-
system-level-programming-with-go-7206744

ebooknice.com

(Ebook) Kubernetes Operators by Jason Dobies, Joshua Wood ISBN 9781492048053,


1492048054

https://ebooknice.com/product/kubernetes-operators-10842206

ebooknice.com

(Ebook) Programming Kubernetes: Developing Cloud-Native Applications by Michael


Hausenblas, Stefan Schimanski ISBN 9781492047100, 1492047104

https://ebooknice.com/product/programming-kubernetes-developing-cloud-native-
applications-10443412

ebooknice.com

(Ebook) Kubernetes for Serverless Applications: Implement FaaS by Effectively


Deploying, Managing, Monitoring, and Orchestrating Serverless Applications Using
Kubernetes by Russ McKendrick ISBN 9781788626125, 1788626125

https://ebooknice.com/product/kubernetes-for-serverless-applications-implement-
faas-by-effectively-deploying-managing-monitoring-and-orchestrating-serverless-
applications-using-kubernetes-51982494

ebooknice.com

(Ebook) Ansible for Kubernetes by Example: Automate Your Kubernetes Cluster with
Ansible by Luca Berton ISBN 9781484292853, 1484292855

https://ebooknice.com/product/ansible-for-kubernetes-by-example-automate-your-
kubernetes-cluster-with-ansible-50105068

ebooknice.com
Philippe Martin

Kubernetes Programming with Go


Programming Kubernetes Clients and Operators
Using Go and the Kubernetes API
Philippe Martin
Blanquefort, France

ISBN 978-1-4842-9025-5 e-ISBN 978-1-4842-9026-2


https://doi.org/10.1007/978-1-4842-9026-2

© Philippe Martin 2023

This work is subject to copyright. All rights are solely and exclusively
licensed by the Publisher, whether the whole or part of the material is
concerned, specifically the rights of translation, reprinting, reuse of
illustrations, recitation, broadcasting, reproduction on microfilms or in
any other physical way, and transmission or information storage and
retrieval, electronic adaptation, computer software, or by similar or
dissimilar methodology now known or hereafter developed.

The use of general descriptive names, registered names, trademarks,


service marks, etc. in this publication does not imply, even in the
absence of a specific statement, that such names are exempt from the
relevant protective laws and regulations and therefore free for general
use.

The publisher, the authors, and the editors are safe to assume that the
advice and information in this book are believed to be true and accurate
at the date of publication. Neither the publisher nor the authors or the
editors give a warranty, expressed or implied, with respect to the
material contained herein or for any errors or omissions that may have
been made. The publisher remains neutral with regard to jurisdictional
claims in published maps and institutional affiliations.

This Apress imprint is published by the registered company APress


Media, LLC, part of Springer Nature.
The registered company address is: 1 New York Plaza, New York, NY
10004, U.S.A.
To Mélina and Elsa, my constant source of truth
Introduction
Back in 2017, I was working for a company building video streaming
software. At the end of that year, a small team, including me, got
assigned a new job to work on deploying the Video CDN developed by
the company on Kubernetes. We decided to explore the concept of
Custom Resources and Operators to deploy this CDN.
The current Kubernetes release was 1.9, the concept of Custom
Resource Definition had just been released in 1.7, and the sample-
controller repository was the only documentation we knew of to help
build an Operator. The Kubernetes ecosystem, being especially lively,
had tools appearing in the following months, specifically the
Kubebuilder SDK. Thus, our project was launched.
From that moment on, I spent numerous days exploring how to
build Operators and other programs interacting with the Kubernetes
API. But the damage was done: I had started to learn Kubernetes
programming from specific to general, and it took me a long time to
fully understand the innards of the Kubernetes API.
I have written this book in the hope that it can teach new
Kubernetes developers how to program, from general to specific, with
the Kubernetes API in Go.

Chapters at a Glance
The target reader for this book has some experience working with
REST APIs, accessing them either by HTTP or using clients for specific
languages; and has some knowledge of the Kubernetes platform,
essentially as a user—for example, some experience deploying such
APIs or frontend applications with the help of YAML manifests.
Chapter 1 of the book explores the Kubernetes API and how it
implements the principles of REST. It especially focuses on the
Group-Version-Resource organization and the Kind concept
proposed by the API.
Chapter 2 continues by covering the operations proposed by the API
and the details of each operation, using the HTTP protocol.
Chapters 3 to 5 describe the common and “low-level” Go libraries to
work with the Kubernetes API: the API and API Machinery Libraries.
Chapters 6 and 7 cover the Client-go Library—the high-level library
to work with the Kubernetes API in Go—and how to unit test code
using this library.
At this point in the book, the reader should be comfortable with
building Go applications working with native resources of the
Kubernetes API.
Chapters 8 and 9 introduce the concept of Custom Resources and
how to work with them in Go.
Chapters 10 to 12 cover the implementation of Kubernetes Operators
using the controller-runtime library.
Chapter 13 explores the Kubebuilder SDK, a tool to help develop and
deploy Kubernetes Operators.
By the end of the book, the reader should be able to start building
Kubernetes operators in Go and have a very good understanding of
what happens behind the scenes.
Any source code or other supplementary material referenced by the
author in this book is available to readers on GitHub via the book's
product page, located at https://github.com/Apress/Kubernetes-
Programming-with-Go-by-Philippe-Martin. For more detailed
information, please visit http://www.apress.com/source-code.
Acknowledgments
I would like to thank the whole Anevia “CDN” team who started
working with me on Kubernetes back in 2018: David, Ansou, Hossam,
Yassine, É tienne, Jason, and Michaël. Special thanks to Damien Lucas for
initiating this project and for having trusted us with this challenge.
My discovery of Kubernetes has been much easier and pleasant
thanks to the TGIK channel and its numerous episodes, hosted by Joe
Beda, Kris Nova, and many others. Plus, thanks to all the Kubernetes
community for such a great ecosystem!
Table of Contents
Chapter 1:​Kubernetes API Introduction
Kubernetes Platform at a Glance
OpenAPI Specification
Verbs and Kinds
Group-Version-Resource
Sub-resources
Official API Reference Documentation
The Deployment Documentation
Operations Documentation
The Pod Documentation
One-Page Version of the Documentation
Conclusion
Chapter 2:​Kubernetes API Operations
Examining Requests
Making Requests
Using kubectl as a Proxy
Creating a Resource
Getting Information About a Resource
Getting the List of Resources
Filtering the Result of a List
Deleting a Resource
Deleting a Collection of Resources
Updating a Resource
Managing Conflicts When Updating a Resource
Using a Strategic Merge Patch to Update a Resource
Applying Resources Server-side
Watching Resources
Filtering During a Watch Session
Watching After Listing Resources
Restarting a watch Request
Allowing Bookmarks to Efficiently Restart a watch Request
Paginating Results
Getting Results in Various Formats
Getting Results as a Table
Using the YAML Format
Using the Protobuf Format
Conclusion
Chapter 3:​Working with API Resources in Go
API Library Sources and Import
Content of a Package
types.​go
register.​go
doc.​go
generated.​pb.​go and generated.​proto
types_​swagger_​doc_​generated.​go
zz_​generated.​deepcopy.​go
Specific Content in core/​v1
ObjectReference
ResourceList
Taint
Toleration
Well-Known Labels
Writing Kubernetes Resources in Go
Importing the Package
The TypeMeta Fields
The ObjectMeta Fields
Spec and Status
Comparison with Writing YAML Manifests
A Complete Example
Conclusion
Chapter 4:​Using Common Types
Pointers
Getting the Reference of a Value
Dereferencing a Pointer
Comparing Two Referenced Values
Quantities
Parsing a String as Quantity
Using an inf.​Dec as a Quantity
Using a Scaled Integer as a Quantity
Operations on Quantities
IntOrString
Time
Factory Methods
Operations on Time
Conclusion
Chapter 5:​The API Machinery
The Schema Package
Scheme
Initialization
Mapping
Conversion
Serialization
RESTMapper
Kind to Resource
Resource to Kind
Finding Resources
The DefaultRESTMappe​r Implementation
Conclusion
Chapter 6:​The Client-go Library
Connecting to the Cluster
In-cluster Configuration
Out-of-Cluster Configuration
Getting a Clientset
Using the Clientset
Examining the Requests
Creating a Resource
Getting Information About a Resource
Getting List of Resources
Filtering the Result of a List
Setting LabelSelector Using the Labels Package
Setting Fieldselector Using the Fields Package
Deleting a Resource
Deleting a Collection of Resources
Updating a Resource
Using a Strategic Merge Patch to Update a Resource
Applying Resources Server-side with Patch
Server-side Apply Using Apply Configurations
Building an ApplyConfigurati​on from Scratch
Building an ApplyConfigurati​on from an Existing Resource
Watching Resources
Errors and Statuses
Definition of the metav1.​Status Structure
Error Returned by Clientset Operations
RESTClient
Building the Request
Executing the Request
Exploiting the Result
Getting Result as a Table
Discovery Client
RESTMapper
PriorityRESTMapp​er
DeferredDiscover​yRESTMapper
Conclusion
Chapter 7:​Testing Applications Using Client-go
Fake Clientset
Checking the Result of the Function
Reacting to Actions
Checking the Actions
Fake REST Client
FakeDiscovery Client
Stubbing the ServerVersion
Actions
Mocking Resources
Conclusion
Chapter 8:​Extending Kubernetes API with Custom Resources
Definitions
Performing Operations in Go
The CustomResourceDe​finition in Detail
Naming the Resource
Definition of the Resource Versions
Converting Between Versions
Schema of the Resource
Deploying a Custom Resource Definition
Additional Printer Columns
Conclusion
Chapter 9:​Working with Custom Resources
Generating a Clientset
Using deepcopy-gen
Using client-gen
Using the Generated Clientset
Using the Generated fake Clientset
Using the Unstructured Package and Dynamic Client
The Unstructured Type
The UnstructuredList​Type
Converting Between Typed and Unstructured Objects
The Dynamic Client
Conclusion
Chapter 10:​Writing Operators withthe Controller-Runtime
Library
The Manager
The Controller
Creating a Controller
Watching Resources
A First Example
Using the Controller Builder
A Second Example Using the ControllerBuilde​r
Injecting Manager Resources into the Reconciler
Using the Client
Getting Information About a Resource
Listing Resources
Creating a Resource
Deleting a Resource
Deleting a Collection of Resources
Updating a Resource
Patching a Resource
Updating the Status of a Resource
Patching the Status of a Resource
Logging
Verbosity
Predefined Values
Logger Name
Getting the Logger from Context
Events
Conclusion
Chapter 11:​Writing the Reconcile Loop
Writing the Reconcile Function
Checking Whether the Resource Exists
Implementing the Reconciled Resource
Simple Implementation Example
Conclusion
Chapter 12:​Testing the Reconcile Loop
The envtest Package
Installing envtest Binaries
Using envtest
Defining a ginkgo Suite
Writing the Tests
Test 1
Test 2
Test 3
Test 4
Conclusion
Chapter 13:​Creating an Operator with Kubebuilder
Installing Kubebuilder
Creating a Project
Adding a Custom Resource to the Project
Building and Deploying Manifests
Running the Manager Locally
Personalizing the Custom Resource
Editing the Go Structures
Enabling the Status Subresource
Defining Printer Columns
Regenerating the Files
Implementing the Reconcile Function
Adding RBAC Annotations
Deploying the Operator on the Cluster
Creating a New Version of the Resource
Defining a New Version
Implementing Hub and Convertible
Setting Up the webhook
Updating kustomization Files
Using Various Versions
Conclusion
Index
About the Author
Philippe Martin
has been working with Kubernetes for
five years, first by creating an Operator
to deploy video CDNs into the cloud,
later helping companies deploy their
applications into Kubernetes, then
writing a Client to help developers work
in a Kubernetes environment. Philippe
has passed the CKAD, CKA, and CKS
certifications. He has extensive
experience with distributed systems and
open-source software: he started his
career 20 years ago creating thin clients
based on the Linux kernel and open-
source components. He is currently
working at Red Hat on the Development
Tools team.
Philippe has been active in the development of Kubernetes,
especially its documentation, and participates in the translation of the
official documentation into French, has edited two reference books
about the Kubernetes API and kubectl, and is responsible for the
French translation of the Kubernetes Dashboard. He participated in
Google Season of Docs to create the new Kubernetes API Reference
section of the official documentation and is maintaining it.
About the Technical Reviewers
Bartosz Majsak
writes code for fun and profit while
proudly wearing a red fedora (also
known as the Red Hat). He has been
long-time open-source contributor and
Java developer turned into Golang
aficionado. Bartosz is overly enthusiastic
about coffee, open source, and speaking
at conferences, not necessarily in that
order. One thing that perhaps proves he
is not a total geek is his addiction to
alpine skiing (and running).

Prasanth
is a Blockchain Certified Professional,
Professional Scrum Master, and
Microsoft Certified Trainer who is
passionate about helping others learn
how to use and gain benefits from the
latest technologies. He is a thought
leader and practitioner in Blockchain,
Cloud, and Scrum. He also handles the
Agile Methodology, Cloud, and
Blockchain technology community
initiatives within TransUnion through
coaching, mentoring, and grooming
techniques.
Prasanth is an adjunct professor and
a technical speaker. He was selected as a speaker at the China
International Industry Big Data Expo 2018 by the Chinese government
and also was invited to the International Blockchain Council by the
Government of Telangana and Goa. In addition, he received accolades
from the Chinese government for his presentation at China
International Industry Big Data Expo 2018. Prasanth has published his
Patent, entitled “Digital Educational Certificate Management System
Using IPFS-Based Blockchain.”
To date, he has interacted extensively, reaching more than 50,000
students, mostly within the technical domain. Prasanth is a working
group member of the CryptoCurrency Certification Consortium, the
Scrum Alliance, the Scrum Organization, and the International Institute
of Business Analysis.
© The Author(s), under exclusive license to APress Media, LLC, part of Springer
Nature 2023
P. Martin, Kubernetes Programming with Go
https://doi.org/10.1007/978-1-4842-9026-2_1

1. Kubernetes API Introduction


Philippe Martin1

(1) Blanquefort, France

Kubernetes is a platform to orchestrate containers operating in the


declarative mode. There are one-thousand-and-one ways to describe
how the Kubernetes platform is constructed. This book focuses on
programming with the platform.
The entry point of the Kubernetes platform is the API. This chapter
explores the Kubernetes architecture by highlighting the central role of
the Kubernetes API. It then focuses on the HTTP REST nature of the
Kubernetes API, and on the extensions added to organize the many
resources managed by it.
Finally, you will learn how to navigate the reference documentation
effectively to be able to extract the maximum quantity of useful
information daily.

Kubernetes Platform at a Glance


On one side of the chain, the user declares the high-level resources to
build applications to deploy: Deployments, Ingresses, and so on.
In the middle, controllers are activated to transform these resources
into low-level resources (Pods), and the scheduler distributes these
resources into nodes. On the other side of the chain, the node agents
deploy the low-level resources onto nodes.
The main elements of the Kubernetes platform (commonly called
the control-plane) are highlighted in Figure 1-1 and described in the
following:
1. The API server – this is the central point on the control-plane; the
user and the various pieces of the control-plane contact this API to
create, get, delete, update, and watch resources.

2. The etcd database – this is only accessible by the API Server, is used
to persist the data relative to resources.

3. The Controller manager – this runs the controllers that transform


high-level resources declared by the user into low-level resources
to be deployed on nodes. The controllers are connected to the API
Server, watching for high-level resources and creating, deleting, and
updating low-level resources to satisfy the specifications declared
in high-level resources.

4. Scheduler – this distributes the low-level resources on the various


nodes. The Scheduler is connected to the API Server to watch for
unaffected resources and connect them to nodes.

5. Kubelet – this is an agent running on all nodes of the cluster, and


each agent manages the workloads affected to its node. The kubelet
is connected to the API Server to watch for Pods resources affected
to its node and to deploy the associated containers using the local
container runtime.

6. Kube proxy – this is an agent running on all nodes of the cluster,


and each agent manages the network configurations affected to its
node. The kube proxy is connected to the API Server to watch for
Service resources and to configure associated network rules on its
node.
Figure 1-1 The architecture of Kubernetes

OpenAPI Specification
The Kubernetes API is an HTTP REST API. The Kubernetes team
provides a specification for this API in the OpenAPI format, either in v2
format at
https://github.com/kubernetes/kubernetes/tree/mast
er/api/openapi-spec or in Kubernetes v1.24, in v3 format, at
https://github.com/kubernetes/kubernetes/tree/mast
er/api/openapi-spec/v3.
These specifications also are accessible from the API Server at these
paths: /openapi/v2 and /openapi/v3.
An OpenAPI specification is made up of various parts and, among
these, are a list of paths and a list of definitions. The paths are the URLs
you use to request this API, and for each path, the specification gives
the distinct operations such as get, delete, or post. Then for each
operation, the specification indicates what are the parameters and body
format for the request, and what are the possible response codes and
associated body format for the response.
The parameters and bodies for requests and responses can be
either simple types or, more generally, structures containing data. The
list of definitions includes data structures that help build the
parameters and bodies for the operations’ requests and responses.
Figure 1-2 is a simplified view of a specification for a User API. This
API can accept two different paths: /user/{userId} and /user. The first
path, /user/{userId}, can accept two operations, get and delete,
respectively, to receive information about a specific user, given its user
ID; and to delete information about a specific user, given its user ID. The
second path, /user, can accept a single operation, post, to add a new
user, given its information.
In this API, a definition of a structure User is given, describing the
information for a user: its ID, first name, and last name. This data
structure is used in the response body of the get operation on the first
path, and in the request body of the post operation on the second path.
Figure 1-2 A simplified user API specification

Verbs and Kinds


The Kubernetes API adds two concepts to this specification: the
Kubernetes API Verbs and the Kubernetes Kinds.
The Kubernetes API Verbs are mapped directly to the operations in
the OpenAPI specification. The defined verbs are get, create, update,
patch, delete, list, watch, and deletecollection. The correspondence
with the HTTP verbs can be found in Table 1-1.
Table 1-1 Correspondence Between Kubernetes API Verbs and HTTP Verbs

Kubernetes API Verb HTTP Verb


get GET
create POST
update PUT
patch PATCH
delete DELETE
list GET
watch GET
deletecollection DELETE
The Kubernetes Kinds are a subset of the definitions in the OpenAPI
specification. When requests are made to the Kubernetes API, data
structures are exchanged through the bodies of requests and responses.
These structures share common fields, apiVersion and kind, to help
the participants of the request recognize these structures.
If you wanted to make your User API manage this Kind concept, the
User structure would contain two additional fields, apiVersion and
kind—for example, with values v1 and User. To determine whether a
definition in the Kubernetes OpenAPI specification is a Kubernetes
Kind, you can look at the x-kubernetes-group-version-kind field of
the definition. If this field is defined, the definition is a kind, and it gives
you the values of the apiVersion and kind fields.

Group-Version-Resource
The Kubernetes API is a REST API, and as a result of that it manages
Resources, and the paths to manage these resources follow the REST
naming conventions—that is, by using a plural name to identify a
resource and by grouping these resources.
Because the Kubernetes API manages hundreds of resources, they
are grouped together, and because the API evolves, the resources are
versioned. For these reasons, each resource belongs to a given Group
and Version, and each resource is uniquely identified by a Group-
Version-Resource, commonly known as GVR.
To find the various resources in the Kubernetes API, you can browse
the OpenAPI specification to extract the distinct paths. Legacy
resources (e.g., pods or nodes) will have been introduced early in the
Kubernetes API and all belong to the group core and the version v1.
The paths to manage legacy resources cluster-wide follow the
format /api/v1/<plural_resource_name>—for example,
/api/v1/nodes to manage nodes. Note that the core group is not
represented in the path. To manage resources in a given namespace, the
path format is
/api/v1/namespaces/<namespace_name>/<plural_resource_nam
e>—for example, /api/v1/namespaces/default/pods to manage
pods in the default namespace.
Newer resources are accessible through paths following the format
/apis/<group>/<version>/<plural_resource_name> or
/apis/<group>/<version>/namespaces/<namespace_name>/<plu
ral_resource_name>.
To summarize, the formats of the various paths to access resources
are:
/api/v1/<plural_name> – to access legacy non-namespaced
resources
Ex: /api/v1/nodes to access non-namespaced nodes resources
or
To access legacy namespaced resources cluster-wide
Ex: /api/v1/pods to access pods across all namespaces
/api/v1/namespaces/<ns>/<plural_name> – to access legacy
namespaced resources in a specific namespace
Ex: /api/v1/namespaces/default/pods to access pods in the
default namespace
/apis/<group>/<version>/<plural_name> – to access non-
namespaced resources in specific group and version
Ex: /apis/storage.k8s.io/v1/storageclasses to access non-
namespaced storageclasses (group storage.k8s.io, version v1)
or
To access namespaced resources cluster-wide
Ex: /apis/apps/v1/deployments to access deployments across
all namespaces
/apis/<group>/<version>/namespaces/<ns>/<plural_name> – to
access namespaced resources in a specific namespace
Ex: /apis/apps/v1/namespaces/default/deployments to
access deployments (group apps, version v1) in the default
namespace

Sub-resources
Following the REST API convention, the resources can have sub-
resources. A sub-resource is a resource that belongs to another and can
be accessed by specifying its name after the name of the resource, as
follows:
/api/v1/<plural>/<res-name>/<sub-resource>
Ex: /api/v1/nodes/node1/status
/api/v1/namespaces/<ns>/<plural>/<res-name>/<sub-resource>
Ex: /api/v1/namespaces/ns1/pods/pod1/status
/apis/<group>/<version>/<plural>/<res-name>/<sub-resource>
Ex: /apis/storage.k8s.io/v1/volumeattachments/volatt1/status
/apis/<grp>/<v>/namespaces/<ns>/<plural>/<name>/<sub-res>
Ex: /apis/apps/v1/namespaces/ns1/deployments/dep1/status
Most Kubernetes resources have a status sub-resource. You can see,
when writing operators, that the operator needs to update the status
sub-resource to be able to indicate the state of this resource observed
by the operator. The operations that can be executed in the status sub-
resource are get, patch, and update. The Pod has more sub-resources,
including attach, binding, eviction, exec, log, portforward, and
proxy. These sub-resources are useful for getting information about a
specific running pod, or executing some specific operation on a running
pod, and so on.
The resources that can Scale (i.e., deployments, replicasets, etc.)
have a scale sub-resource. The operations that can be executed in the
scale sub-resource are get, patch, and update.

Official API Reference Documentation


The official reference documentation of the API can be found at
https://kubernetes.io/docs/reference/kubernetes-
api/. The resources managed by the API are first grouped together by
category (i.e., workloads, storage, etc.), and for each category, you can
obtain a list of resource names with a short description (Figure 1-3).
Note that these categories are not part of the Kubernetes API
definition but are used in this website to help inexperienced users find
their way into the multitude of available resources.

Figure 1-3 The Kubernetes resources grouped by category

To be precise, the name displayed is not the resource name in the


REST sense, but the associated principal kind, as shown in Figure 1-4.
For example, when managing Pods, the resource name used in the REST
paths is pods (i.e., lowercase and plural), and the definition used to
exchange information about Pods during HTTP requests is named Pod
(i.e., uppercase and singular). Note that other kinds can be associated
with the same resource. In the example in this chapter, the PodList kind
(used to exchange information about Lists of Pods) also exists.

Figure 1-4 The resources for a specific category, with a short description

The Deployment Documentation


Let’s explore the reference page for the Deployment available at this
address:
https://kubernetes.io/docs/reference/kubernetes-
api/workload-resources/deployment-v1/. The title of the
page, Deployment, is the principal kind associated with the
deployments resource shown in Figure 1-5.
Figure 1-5 The Deployment documentation page
The apiVersion indicated in the header can help you write a YAML
manifest for a Deployment resource because you need to specify, for
each resource in a Kubernetes manifest, the apiVersion and kind.
In this case, you know the manifest for a deployment will start with
the following:

apiVersion: apps/v1
kind: Deployment

The next header line indicates the import to use when writing Go
code. In Chapter 3, you will see how to use this import when describing
resources in Go.

After the header, a list of structure definitions is described, also


accessible from the table of contents for the Deployment
documentation page in Figure 1-6. The first one is the principal kind of
the resource, optionally followed by structure definitions that are used
in fields of the first kind.

Figure 1-6 Table of contents for the Deployment documentation page


For example, the Deployment kind contains a spec field, of type
DeploymentSpec, which is described later. Note that DeploymentSpec
is not a structure directly exchanged during HTTP requests, and for
that, it is not a kind and does not contain kind or apiVersion fields.
Following the principal kind, and its associated definitions, other
kinds associated with the resource are displayed. In this case, the
DeploymentList kind.
Operations Documentation
The next subject in the API Documentation for a resource is the list of
possible operations on this resource or its sub-resources, also
accessible from the table of contents page (see Figure 1-6). By
examining the details for the create operation to Create a Deployment,
as shown in Figure 1-7, you can see the HTTP Request verb and path to
use, the parameters to pass during the request, and the possible
responses. The HTTP verb to use for the request is POST and the path
is /apis/apps/v1/namespaces/{namespace}/deployments.
Figure 1-7 Details for a “create” Deployment operation
The {namespace} part of the path indicates a path parameter,
which is to be replaced by the name of the namespace on which you
want to create the deployment. You can specify the query parameters:
dryRun, fieldManager, fieldValidation, and pretty. These parameters
will follow the path with the format path?dryRun=All.
The body of the request must be a Deployment kind. When using
kubectl, you are writing Kubernetes Manifests that contain this body. In
Chapter 3, you will see how to build the body in Go. The possible HTTP
codes for the responses are: 200, 201, 202, and 401; and for the 2xx
codes, the response body will contain a Deployment kind.

The Pod Documentation


Some structures contain many fields. For them, the Kubernetes API
documentation categorizes the fields. An example is the documentation
of the Pod resource.
The documentation page for the Pod resource first contains the
description for the principal kind, Pod, followed by the description of
the PodSpec structure. The PodSpec structure contains about 40
fields. To help you understand the relationships between these fields
and to simplify their exploration, they are arranged into categories. The
PodSpec fields’ categories are the following: Containers, Volumes,
Scheduling, Lifecycle, and so on.
Additionally, for fields containing nested fields, descriptions of them
are generally displayed inline to avoid a back and forth between
structure descriptions. For complex structures, however, the
description is reported subsequently on the page, and a link is present
next to the field name to be able to access it easily.
This is always the case for the Spec and Status structures because
they are very commonly found in almost all the resources. In addition,
this is the case for some structures used in the Pod kind—for example,
Container, EphemeralContainer, LifecycleHandler, NodeAffinity,
and so on.
Some structures used in several resources are placed in the
Common Definitions section, and a link is present next to the field name
to access it easily. In Figure 1-8, you can see the Containers category
inside the description of the PodSpec structure.
Figure 1-8 Extract of the PodSpec structure documentation
You also can see that the fields, containers and initContainers, are
of the same type as Container, which is described later on the page and
is accessible with a link. The imagePullSecrets field is of type
LocalObjectReference, which is described in the Common Definitions
section and also is accessible through a link.

One-Page Version of the Documentation


Another version of the API Reference documentation exists and is
presented on a single page. This version covers all the versions of the
resources served by a Kubernretes version (not just the latest one).
This version (if you want, change the last part of the path to navigate to
another Kubernetes version) can be found at the following URL:
https://kubernetes.io/docs/reference/generated/k
ubernetes-api/v1.24/

Conclusion
In this chapter, you have been able to discover the architecture of the
Kubernetes platform, and that the API Server plays a central role. The
Kubernetes API is an HTTP REST API, and the resources are categorized
into various versioned groups.
Kinds are specific structures used to exchange data between the API
server and the clients. You can browse, using the official Kubernetes
website, the API specifications in a human-readable form to discover
the structure of the various resources and kinds, the different
operations available for each resource and sub-resource, and their
associated verbs.
© The Author(s), under exclusive license to APress Media, LLC, part of Springer Nature 2023
P. Martin, Kubernetes Programming with Go
https://doi.org/10.1007/978-1-4842-9026-2_2

2. Kubernetes API Operations


Philippe Martin1

(1) Blanquefort, France

The previous chapter described that the Kubernetes API follows REST principles and
enables users to manipulate resources.
In this chapter, you will learn how to perform various operations by making HTTP
requests directly. During your daily work, you probably will not have to interact
directly with the HTTP layer, but it is important to understand how the API works at
this level so that you can understand how to use more easily it with a higher-level
library.

Examining Requests
Before starting to write your own HTTP requests, you can examine with kubectl
which requests are used when executing kubectl commands. This can be achieved by
using the verbose flag, -v, with a value greater than or equal to 6. Table 2-1 shows
which information is displayed at each level.
For example, if you want to know the URL that is called when getting pods for all
namespaces, you can use the following command:

$ kubectl get pods --all-namespaces -v6


loader.go:372] Config loaded from
file: /home/user/.kube/config
round_trippers.go:553] GET
https://192.168.1.194:6443/api/v1/pods?limit=500 200 OK in
745 milliseconds

In the output of the command, you can see that the path used is /api/v1/pods.
Or, when getting pods in a specific namespace, you can see that the path used is
/api/v1/namespaces/default/pods:

$ kubectl get pods --namespace default -v6


loader.go:372] Config loaded from
file: /home/user/.kube/config
round_trippers.go:553] GET
https://192.168.1.194:6443/api/v1/namespaces/default/pods?
limit=500 200 OK in 138 milliseconds

Table 2-1 Verbosity Levels

Level Method Request Events Request Response Response Curl Body


and URL timing timing headers status headers cmd length
-v 6 yes yes – – – – – 0
-v 7 yes – – yes yes – – 0
-v 8 yes – – yes yes yes - ≤ 1024
-v 9 yes yes yes – – yes yes ≤ 10240
-v 10 yes yes yes – – yes yes ∞

Making Requests
This section examines all the possible operations you can do with Kubernetes
resources.

Using kubectl as a Proxy


You must be authenticated to make requests to the Kubernetes API of a cluster,
unless your cluster accepts unauthentified requests, which is unlikely.
A way to run authenticated HTTP requests is to use kubectl as a proxy to make it
deal with the authentication. For this, the kubectl proxy command can be used:

$ kubectl proxy
Starting to serve on 127.0.0.1:8001

On a new terminal, you can now run your HTTP requests without any
authentication. Next, a HOST variable to access the proxy is defined:

$ HOST=http://127.0.0.1:8001

Creating a Resource
You can create a new resource by first creating a Kubernetes manifest describing this
resource—for example, to create a Pod, you can write:

$ cat > pod.yaml <<EOF


apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- image: nginx
name: nginx
EOF
You then need to pass the resource description into the body of a POST request
(note that the -X POST flag can be omitted because the --data-binary flag is being
used). For example, to create a pod resource use:

$ curl $HOST/api/v1/namespaces/project1/pods
-H "Content-Type: application/yaml"
--data-binary @pod.yaml

This is equivalent to running the kubectl command:

$ kubectl create --namespace project1 -f pod.yaml -o json

Note that the namespace is not indicated in the pod.yaml file. If you add it, you
must specify the same namespace in the YAML file and in the path, or you will get an
error—that is, the namespace of the provided object does not match the namespace
sent on the request.

Getting Information About a Resource


You can obtain information about a specific resource using a GET request and
passing its name as a parameter (and its namespace if it is a namespaced resource)
in the path. In this example, you will request the information for the pod named
nginx in the project1 namespace:

$ curl -X GET
$HOST/api/v1/namespaces/project1/pods/nginx

This will return information about the resource in the JSON format, using the
kind associated with this resource as a structure; in this example, it is a Pod kind.
This is equivalent to running the kubectl command:

$ kubectl get pods --namespace project1 nginx -o json

Getting the List of Resources


For namespaced resources, you can get the list of resources either cluster-wide or in
a specific namespace. For non-namespaced resources, you can get the list of
resources. In any case, you will use a GET request.

Cluster-wide
To get the list of resources cluster-wide, for namespaced or non-namespaced
resources; for example, for the pod resource, use the following:
$ curl $HOST/api/v1/pods
This will return information about the list of pods in all namespaces, using a
PodList kind. This is equivalent to running the kubectl command:

$ kubectl get pods --all-namespaces -o json

In a Specific namespace
To get the list of resources in a specific namespace, you need to indicate the
namespace in the path; for example, for the pod resource, use this:

$ curl $HOST/api/v1/namespaces/project1/pods

This will return information about the list of pods in the project1 namespace,
using a PodList kind. This is equivalent to running the kubectl command:

$ kubectl get pods --namespace project1 -o json

Filtering the Result of a List


When running a list request, you get as a result the complete list of resources of this
kind, in the specified namespace or cluster-wide, depending on your request.
You may want to filter the result. The most common way to filter resources in
Kubernetes is to use labels. For this, resources need to have defined labels; then,
during a list request, you can define some label selectors. It also is possible to filter
resources based on a limited set of fields by using field selectors.

Using Label Selectors


All Kubernetes resources can define labels. For example, when creating pods, you can
define some labels with kubectl:

$ kubectl run nginx1 --image nginx --labels mylabel=foo


$ kubectl run nginx2 --image nginx --labels mylabel=bar

This results in pods with labels defined in the metadata part of the resource:

$ kubectl get pods nginx1 -o yaml


apiVersion: v1
kind: Pod
metadata:
labels:
mylabel: foo
name: nginx1
[...]

$ kubectl get pods nginx2 -o yaml


apiVersion: v1
kind: Pod
metadata:
labels:
mylabel: bar
name: nginx2
[...]
Now, when running a list request, you can define some label selectors to filter
these resources by using the labelSelector query parameter, which can contain a
comma-separated list of selectors.
Select all the resources defining a specific label, no matter its value; for example,
the mylabel label:

$ curl $HOST/api/v1/namespaces/default/pods?
labelSelector=mylabel

Select all resources not defining a specific label; for example, the mylabel label:

$ curl $HOST/api/v1/namespaces/default/pods?
labelSelector=\!mylabel

Note the exclamation point (!) before the label name—the backslash character (\)
is being used because the exclamation point is a special character for the shell.
Select all resources defining a label with a specific value; for example, mylabel
having the value foo:

$ curl $HOST/api/v1/namespaces/default/pods?
labelSelector=mylabel==foo

or

$ curl $HOST/api/v1/namespaces/default/pods?
labelSelector=mylabel=foo

Select all resources defining a label with a value different from a specific one; for
example, the label mylabel having a value different from foo:

$ curl $HOST/api/v1/namespaces/default/pods?
labelSelector=mylabel\!=foo

Note the exclamation point (!) before the equal sign (=)—the backslash character
(\) is being used because the exclamation point is a special character for the shell.
Select all resources defining a label with a value in a set of values; for example,
the label mylabel having one of the values foo or baz:

$ curl $HOST/api/v1/namespaces/default/pods?
labelSelector=mylabel+in+(foo,baz)

Note the plus characters (+) that encodes spaces in the URL. The original selector
being: mylabel in (foo,baz).
Select all resources defining a label with a value not in a set of values; for
example, the label mylabel having a value different from foo or baz:

$ curl $HOST/api/v1/namespaces/default/pods?
labelSelector=mylabel+notin+(foo,baz)

Note the plus characters (+) that encodes spaces in the URL. The original selector
being: mylabel not in (foo,baz).

You can combine several selectors by separating them with a comma. This will act
as an AND operator. For example, to select all resources with a label mylabel
defined and a label otherlabel being equal to bar, you can use the following label
selector:

$ curl $HOST/api/v1/namespaces/default/pods?
labelSelector=mylabel,otherlabel==bar

Using Field Selectors


You can filter resources using a limited set of fields. For all resources, you can filter
on the metadata.name field; and for all namespaced resources, you can filter on the
metadata.namespace field.
Here is the list of additional fields available for filtering, depending on resources,
for Kubernetes 1.23:
core.event:
involvedObject.apiVersion
involvedObject.fieldPath
involvedObject.kind
involvedObject.name
involvedObject.namespace
involvedObject.resourceVersion
involvedObject.uid
reason
reportingComponent
source
type
core.namespace:
status.phase
core.node:
spec.unschedulable
core.pod:
spec.nodeName
spec.restartPolicy
spec.schedulerName
spec.serviceAccountName
status.nominatedNodeName
status.phase
status.podIP
core.replicationcontroller:
status.replicas
core.secret:
type
apps.replicaset:
status.replicas
batch.job:
status.successful
certificates.certificatesigningrequest:
spec.signerName
Now, when running a list request, you can indicate some field selectors to filter
these resources by using the fieldSelector parameter, which can contain a
comma-separated list of selectors.
Select all resources for which a field has a specific value; for example, the field
status.phase having the value Running:

$ curl $HOST/api/v1/namespaces/default/pods?
fieldSelector=status.phase==Running
or

$ curl $HOST/api/v1/namespaces/default/pods?
fieldSelector=status.phase=Running

Select all resources for which a field has a value different from a specific one; for
example, the field status.phase having a value different from Running:

$ curl $HOST/api/v1/namespaces/default/pods?
fieldSelector=status.phase\!=Running

Note the exclamation point (!) before the equal sign (=)—the backslash character
(\) is being used because the exclamation point is a special character for the shell.

You can combine several selectors by separating them with a comma. This will act
as an AND operator. For example, to select all pods with a phase being equal to
Running and a restart policy not being Always, you can use this field selector:

$ curl $HOST/api/v1/namespaces/default/pods?
fieldSelector=status.phase==Running,
spec.restartPolicy\!=Always

Deleting a Resource
To delete a resource, you need to specify its name (and namespace for namespaced
resources) in the path and use a DELETE request. For example, to delete a pod, use
the following:

$ curl -X DELETE
$HOST/api/v1/namespaces/project1/pods/nginx

This will return the information about the deleted resource in the JSON format,
using the kind associated with the resource—in this case, a Pod kind.
This is equivalent to running the kubectl command (except that you cannot get
information about the deleted resource, only its name with the -o name flag):

$ kubectl delete pods --namespace project1 nginx

Deleting a Collection of Resources


It also is possible to delete a collection of a given resource in a specific namespace,
using a DELETE request; and, for namespaced resources, indicating the namespace
in the path:

$ curl -X DELETE
Random documents with unrelated
content Scribd suggests to you:
CHAPTER XIV.

SLAVE BARRACOONS—A BIG SNAKE UNDER MY BED—A


SLAVE SHIP OFF THE COAST.

One day I passed by an immense enclosure, protected by a fence of


palisades about twelve feet high, and sharp-pointed at the top.
Passing through the gate, which was standing open, I found myself
in the midst of a large collection of shanties, surrounded by shady
trees, under which were lying, in various positions, a great many
negroes. As I walked round, I saw that the men were fastened, six
together, by a little stout chain, which passed through a collar
secured about the neck of each. Here and there were buckets of
water for the men to drink; and they being chained together, when
one of the six wanted to drink, the others had to go with him.
Then I came to a yard full of women and children. These could roam
at pleasure through their yard. No men were admitted there. These
people could not all understand each other's language; and you may
probably wish to know who they were. They were Africans belonging
to various tribes, who had been sold, some by their parents or by
their families; others by the people of their villages. Some had been
sold on account of witchcraft; but there were many other excuses
for the traffic. They would find suddenly that a boy or girl was "dull,"
and so forth, and must be sold. Many of them came from countries
far distant.
Some were quite merry; others appeared to be very sad, thinking
that they were bought to be eaten up. They believed that the white
men beyond the seas were great cannibals, and that they were to be
fattened first and then eaten. In the interior, one day, a chief
ordered a slave to be killed for my dinner, and I barely succeeded in
preventing the poor wretch from being put to death. I could hardly
make the chief believe that I did not, in my own country, live on
human flesh.
Under some of the trees were huge caldrons, in which beans and
rice were cooking for the slaves; and others had dried fish to eat. In
the evening they were put into large sheds for the night. One of the
sheds was used as a hospital.
In the midst of all this stood the white man's house—yes, the white
man's house!—and in it were white men whose only business was to
buy these poor creatures from the Oroungou people!
After I had seen everything, I left the barracoon—for that is the
name given to such a place as I have just described. I wandered
about, and it was dark before I returned to the little bamboo house
which the king had given me. I got in, and then, striking a match
carefully, I lighted a torch, so that I might not go to bed in darkness.
You may smile when I say bed, for my couch was far from bearing
any resemblance to our beds at home, with mattresses and pillows,
and sheets and blankets. Travellers in equatorial Africa are utter
strangers to such luxuries.
After I had lighted the torch, I cast my eyes round to see if anything
had been disturbed; for a thief, so disposed, could easily break into
these houses. I noticed something glittering and shining under my
akoko, or bedstead. The object was so still that I did not pay any
attention to it; in fact, I could not see it well by the dim light of the
torch. But when I approached the bed to arrange it, I saw that the
glitter was produced by the shining scales of an enormous serpent,
which lay quietly coiled up there within two feet of me. What was I
to do? I had fastened my door with ropes. If the snake were to
uncoil itself and move about, it might, perhaps, take a spring and
wind itself about me, quietly squeeze me to death, and then swallow
me as he would a gazelle. These were not comforting thoughts. I
was afraid to cry out for fear of disturbing the snake, which
appeared to be asleep. Besides, no one could get in, as I had
barricaded the only entrance, so I went quietly and unfastened the
door. When everything was ready for a safe retreat, I said to myself,
"I had better try to kill it." Then, looking for my guns, I saw, to my
utter horror, that they were set against the wall at the back of the
bed, so that the snake was between me and them. After watching
the snake intently, and thinking what to do, I resolved to get my
gun; so, keeping the door in my rear open, in readiness for a speedy
retreat at the first sign of life in the snake, I approached on tip-toe,
and, in a twinkling of an eye, grasped the gun which was loaded
heavily with large shot. How relieved I felt at that moment! I was no
longer the same man. Fortunately, the snake did not move. With my
gun in one hand I went again towards the reptile, and, fairly placing
the muzzle of the gun against it, I fired, and then ran out of the
house as fast as I could.
At the noise of the gun there was a rush of negroes from all sides to
know what was the matter. They thought some one had shot a man,
and run into my house to hide himself; so they all rushed into it,
helter-skelter; but I need not tell you they rushed out just as fast, on
finding a great snake writhing about on the floor. Some had trodden
upon it and been frightened out of their wits. You have no idea how
they roared and shouted; but no one appeared disposed to enter the
house again, so I went in cautiously myself to see how matters
stood, for I did not intend to give undisputed possession of my hut
so easily to Mr. Snake. I entered and looked cautiously around. The
dim light of the torch helped me a little, and there I saw the snake
on the ground. Its body had been cut in two by the discharge, and
both ends were now flapping about the floor. At first I thought these
ends were two snakes, and I did not know what to make of it; but
as soon as I perceived my mistake, I gave a heavy blow with a stick
on the head of the horrible creature, and finished it. Then I saw it
disgorge a duck—a whole duck—and such a long duck! It looked like
an enormous long-feathered sausage. After eating the duck, the
snake thought my bedroom was just the place for him to go to sleep
in and digest his meal; for snakes, after a hearty meal, always fall
into a state of torpor. It was a large python, and it measured—would
you believe it?—eighteen feet. Fancy my situation if this fellow had
sprung upon me and coiled round me! It would soon have been all
over with me. I wonder how long it would have taken to digest me,
had I been swallowed by the monster!
One fine day, while walking on the beach of this inhospitable shore, I
spied a vessel. It approached nearer and nearer, and at last ran in
and hove-to a few miles from the shore. Immediately I observed a
gang of slaves rapidly driven down from one of the barracoons. I
stood and watched. The men were still in gangs of six, but they had
been washed, and each had a clean cloth on. The canoes were
immense boats, with twenty-six paddles, and about sixty slaves
each. The poor slaves seemed much terrified. They had never been
on the rough water before, and they did not know what that dancing
motion of the sea was. Then they were being taken away, they knew
not whither. As they skimmed over the waves and rolled, now one
way, now another, they must have thought their last day had come,
and that they were to be consigned to a watery grave.
I was glad that these poor creatures could not see me, for I was
hidden from their view by trees and bushes. I felt ashamed of myself
—I actually felt ashamed of being a white man! Happily, such scenes
are rarely if ever witnessed nowadays, and the slave trade will soon
belong to the past.
Two hours afterwards, the vessel, with a cargo of six hundred slaves,
was on her way to Cuba.
THE GAZELLE.
CHAPTER XV.

GOING INTO THE INTERIOR—SLEEPING WITH THE KING'S


RATS—THE CHIMPANZEE—KILL A GAZELLE—TOO COLD TO
SLEEP—THE GREY PARTRIDGE.

After this I went again to visit King Bango, and was announced to
his Majesty by his great mafouga. I had an important object in
paying this visit. I wished to ask the king to permit me to go into the
interior and to spare me some people to show me the way.
Bango liked me, though I had declined to marry one of his beautiful
daughters. So he granted my request, and gave me twenty-five
men, some of whom were reputed great hunters in that country.
They had killed many elephants and brought all the ivory to their
king. They were the providers of the royal table, and passed their
lives in the hunt and in the forest.
We made great preparations for the chase, for game was said to be
plentiful. We were to encamp many days in the forest, and to have a
jolly time, and a hard time, too, for the hunter's life is not an easy
one. I was invited by the king to sleep in his palace, so that the next
day I might start early; so I was led to my bedroom by the great
mafouga. It was so dirty and gloomy that I wished myself fast
asleep under a tree in the forest. I looked around, thinking that
perhaps the king wanted to get rid of me, and had invited me there
to have me murdered; but finding nothing suspicious, I concluded
that old King Bango had never entertained such ideas, and I felt
vexed at myself for having such thoughts on my mind. Then I
extinguished the light and lay down on the royal couch. I had
scarcely lain down when I began to hear a strange noise. At first I
did not know what it meant. The noise in the room increased. What
could it be? I tried to see through the darkness, but could distinguish
nothing. Just then I felt something getting under my blanket.
Confounded, I jumped up, not knowing what it might be. It was an
enormous rat. As soon as I got up, I heard a perfect scrambling of
rats going back where they came from, and then all became silent. I
lay down on the bed again and tried to sleep, but in vain, on account
of the assaults and gambols of the rats, of which there was a
prodigious number. They seemed inclined to dispute possession of
my room with me. They were continually on my bed, and running
over my face. I soon got quite enough of the royal palace. I wished I
had never come into it. But it was an excellent place for getting up
early. No sooner had the morning twilight made its appearance than
I rose and called my men together; and, though we could hardly
see, we set out at once on the march.
I went in advance with Aboko, my head man, and Niamkala, the
next best man, at my side. Both these men were great hunters, and
had spent the principal part of their lives in the woods. They seemed
really like men of the woods, so very wild were their looks. Aboko
was a short, somewhat stout man; very black, and extremely
muscular, very flat-nosed, and with big thick lips. His eyes were large
and cunning, and seemed to wander about; his body bore marks of
many scratches from thorny trees and briars; his legs displayed
great strength. Niamkala, on the contrary, was tall and slender, not
very dark; he had sharp piercing eyes, and seemed to be continually
looking after something. Both were first-rate elephant hunters.
Aboko, Niamkala, and I became great friends, for we were all three
hunters, and loved the woods.
Our way led through some beautiful prairies, each surrounded by
dark forests, and seeming like natural gardens planted in this great
woody wilderness. The country was really lovely. The surface was
mostly rolling prairie, with a light sandy soil. The highest hills often
broke into abrupt precipices, on which we would come suddenly;
and if any of us had tumbled down to the bottom, he would never
have been heard of again. The woods are the safe retreat of the
elephant. Great herds of buffaloes are found there, also antelopes,
which go out into the great grass fields by night to play and feed.
Leopards are also abundant.
I was much pleased to be able to travel in an open space, and not
always through the dark forest The breeze fanned our faces as we
went onward. Presently we saw the footprints of huge elephants and
of wild buffaloes. Friend Aboko now warned us to look sharp, for we
were sure to see game. Sure enough, he had hardly spoken when
we saw a bull standing, deer-like, upon the edge of the wood,
watching us, I suppose, and no doubt greatly puzzled to make out
what kind of animals we were. He stood for some minutes, safe out
of range, and then turned into the woods, evidently not liking our
appearance. We ran around to intercept him; and I waited at one
pass in the woods, for Aboko to go clear around and drive the bull
towards me.
I was waiting, when suddenly I saw something approaching me out
of the deep gloom of the forest. I thought it was Aboko coming
towards me, and I waited anxiously for news. I did not say a word
for fear of frightening the game that might be near us. The object
came nearer and nearer to me, till I thought I could recognise
Aboko's dark face distinctly through the foliage. I stood with my gun
resting on the ground, when suddenly I heard a shrill scream, and
then what I thought to be Aboko turned and ran back into the
woods, showing a broad, big hairy body. It was one of the wild men
of the woods—the chimpanzee—and a big one it was, I assure you.
How glad I was to have seen this wild man of the woods! For a few
minutes I felt so astonished that I did not move. His black face
certainly did look very much like that of an African, so much so that,
as I have already said, I took the chimpanzee to be Aboko.
By-and-by the real Aboko made his appearance. This time there was
no illusion, and we had a good laugh over my mistake. I felt quite
vexed that I had not shot the chimpanzee. I should have liked so
much to look at the animal closely. But I felt it was almost like
shooting a man.
We left the woods, and started once more for the interior. We had
not been long on our way when I spied a gazelle right in the middle
of the prairie. How could one approach it without being seen? for
the grass was short. We wanted very much to kill it, for we had not
killed anything yet; and what were we to have for our dinner and
supper? No one likes to go without dinner, especially when working
hard. Aboko, Niamkala, and I held a council. We lay down flat on the
ground for fear of being seen; and finally it was agreed that I should
go towards the gazelle with my long range gun and shoot it if I
could. So I started. I almost crawled, now and then raising my head
just to the level of the grass, to see if the animal was still there.
When I thought I was near enough, I quietly lay down flat on the
ground and rested my gun on an ant-hill that looked like a
mushroom. Taking careful aim at the unsuspicious animal I fired,
and down it tumbled, to my great delight. Aboko and Niamkala, who
had been watching afar off, came rushing and shouting, their faces
beaming with joy. The prospect of a good dinner cheered them up.
Others of the party soon joined us. The gazelle was cut upon the
spot, and we continued our journey till we came to a beautiful little
stream, which was too deep to be forded. A huge tree had been
felled, and we crossed to the other side on it, though it was hard
work. I assure you I thought once or twice I should have tumbled
into the water.
At sunset we stopped, quite tired out. We made our camp in the
midst of the prairie in order to have the nice grass to lie upon. It was
the dry season, and we were not afraid of getting wet. The people
went into the nearest forest and collected an immense quantity of
firewood, not a difficult task, as so many dead limbs were lying on
the ground.
We lighted a great many large fires, which blazed up fiercely, for the
wind blew hard. The country around was illuminated, and the glare
of our fires must have been seen a long way off. We took our dinner
and supper at the same time. I roasted my own share of the gazelle
myself; I put a piece of stick through the flesh and laid the skewer
across two forked sticks, which I fixed in the ground on each side of
the fire. I longed for some lard to baste the roasting meat, but I was
thankful for the good dinner I had, and I enjoyed it thoroughly. I
had a little bit of salt to eat with it, and also some nice cayenne
pepper.
My men also seemed to enjoy their meal very much, for they had
meat to their heart's content; and these negroes are very gluttonous
generally. It was laughable to see how lazily we lay around on the
grass by our fires; some were smoking, others tried to sleep, while
others told stories; but we all tried to warm ourselves, and kept
continually adding fuel to the already bright fires.
The night was clear and almost frosty. The stars shone brilliantly
above our heads, and it was bright moonlight. It became so windy
and cold that we regretted we had not encamped by the forest,
where we should have been sheltered from the wind. It was too cold
to sleep, even with my blanket; and my poor men, who had no
blankets, were shivering around the fires.
So at two o'clock in the morning I ordered the men to get up. A
couple of hours' sharp walking brought us to a thick wood, and there
we were sheltered. We quickly made up one very large fire, big
enough for all of us, and stretched ourselves pell-mell around it for a
short nap. We were so tired that we soon fell asleep, not caring for
leopards or anything else. We were awakened by the cry of the grey
partridge (Francolinus squamatus), called quani by the natives.
I will now say a word about these partridges. Unlike our partridges,
they perch on trees. When evening comes, the old cock perches
himself first, and calls the flock together. They all settle near each
other. In the morning, before daylight, they begin to cluck; and it
was this noise that we heard. They do not sleep on the ground, like
our partridges, because there are too many snakes crawling about,
and too many carnivorous animals.
AFTER DINNER.
CHAPTER XVI.

THE HIPPOPOTAMUS—A SPECK OF WAR—REACH NGOLA—


A SUNDAY TALK—THE BLACK MAN'S GOD AND THE WHITE
MAN'S GOD—HOW KING NJAMBAI PUNISHED HIS WIFE—
WE BUILD AN OLAKO IN THE WOODS.

Sunrise found us under way again; and before us lay a fine stretch
of prairie, on the farther borders of which were quietly grazing
several herds of buffaloes, which, as we approached them, quickly
ran into the woods. While they remained in sight they gave the
country a civilized appearance; it looked like a large grazing farm in
June, with cattle, and hay almost ready for harvest; a fine, quiet,
old-country picture here in the wilds of Africa, that reminded me so
much of home scenes that I felt happy and elated.
We pushed on rapidly in order to travel as far as possible before the
heat of the day should set in. We came to a large pool or lakelet;
and, while looking at the water, I suddenly saw something strange
coming out from under its surface. It was a hippopotamus—the first
I had seen. I thought it was a log of wood; then I fancied it was the
head of a horse; for certainly, from a distance, the head of a
hippopotamus looks like that of a horse. Then I heard a great grunt,
and down went the head under the water. Suddenly a number of the
animals made their appearance; there were at least a dozen of
them. They began sporting in the water, now popping their huge
heads out and snorting, and then diving to the bottom and
remaining there for some time.
I watched them for a while, and then I took my gun, intending to
send a bullet into the head of one and haul him ashore; but Aboko
said they would sink to the bottom. Not wishing to kill one of these
creatures for nothing, I took Aboko's advice, and we went away.
We had not met a single human being since we left Sangatanga till
now. As we journeyed, I saw in the distance what I at first took to
be a herd of buffaloes, but soon perceived it was a caravan of
natives coming in our direction. Immediately we looked at our guns;
for in this country there is no law, and every man's hand is against
his brother. We saw that they, too, prepared for an encounter; that
most of them hid in the grass, watching. Four fellows came towards
us to reconnoitre, and to ask if it was peace or war, when suddenly
they got a glimpse of me, and I do not know how, but they at once
saw, from the fact of my being there, that there would be no war.
They shouted to their companions to come and see the Otangani.
They were Shekianis, who, as I have said, are a very warlike people,
and this part of the country, I was told, was thickly inhabited by
them. We left them in the midst of their wonders, and travelled as
fast as we could, for we wanted to reach a village of their tribe,
named Ngola, whose chief was a friend of King Bango, and was his
vassal, having married one of his daughters.
At last, after much travelling, we reached the village of Ngola. As we
approached, and as soon as the women caught sight of me, they ran
screaming into the houses. Njambai, the chief, received us very
kindly, and gave me a house to live in.
Ngola was a very pretty village, and the house I lived in belonged to
Shinshooko, the brother of the chief. You will agree with me that
Shinshooko had a funny name. He was a worthy fellow, and
tolerably honest, too, for he gave me the key of one of his doors—(I
wonder where he got the old padlock that was on it)—and he
recommended me to shut my door every time I went away, as the
people might steal something.
Sunday came; I remained in the village. They all understood the
Oroungou language so I could speak to them. I told them there was
no such thing as witchcraft, and that it was very wrong to accuse
people of it and kill them; that there was only one God, who made
both the whites and the blacks, and we should all love Him. This
elicited only grunts of surprise and incredulity. They all shouted that
there were two gods,—the God of the Ntangani (white men) and the
God of the Alombai (black men). The God of the black men had
never given them anything, while the God of the white men had sent
them guns, powder, and many other fine things. Then Shinshooko
remarked, "You have rivers of alongon (rum) flowing through your
land. When I go to Sangatanga I taste it at King Bango's; how much
I should like to live on the banks of such rivers!" They would not
believe that we had only rivers of water like theirs; and that we
ourselves made our powder, and guns, and rum also.
I stayed for a few days in the village of Ngola, where the people
were very kind to me. One day I heard a woman crying out, as if she
were in great pain. Asking what was the matter, a man told me the
king was punishing one of his wives; and others said that, if I did
not go to her help, she might be killed. I hurried to the king's house,
and there, in front of the verandah, a spectacle met my eyes, which
froze my blood with horror. A woman was tied by the middle to a
stout stake driven into the ground. Her legs were stretched out and
fastened to other smaller stakes, and stout cords were bound round
her neck, waist, ankles, and wrists. These cords were being twisted
with sticks; and when I arrived the skin was bursting from the
terrible compression. The poor woman looked at me. The king was
in a perfect rage; he himself was the chief executioner. His eyes
were blood-shot, and his lips were white with foam. I had to be
careful in expostulating with the king, for fear that he might kill her
at once, in a fit of rage. I walked up, and, taking him by the arm, I
asked him for my sake to release the poor woman, and not to kill
her. He seemed to hesitate; he did not answer, and went into his
house. I threatened to leave if he did not release her. Finally he
consented, and said: "Let her loose yourself; I give her to you."
How glad I was! I rushed out immediately and began to untie the
savage cords, and to cut them away with my knife. The poor
creature was covered with blood. I sent her to my house and took
care of her. I learned that she had stolen some of her husband's
beads.
After this, I left the Shekiani village of Ngola and went on my
journey with my friends, Aboko and Niamkala. We travelled on, till,
on reaching a place in the midst of a forest, not far from a little lake,
we determined to build an olako; for I liked the country so much
that I did not want to leave it. There were a great many wild animals
in the neighbourhood, and we thought the place was likely to afford
us good sport, especially as the lake would draw beasts down to its
banks to drink. We were not only near water, but we had a wide
stretch of forest and prairie-land about us. We worked very hard that
day, building and arranging our encampment, in such a way as to
make everything comfortable and secure. Of course we selected the
prettiest part of the forest, and where there were many tall and
shady trees. We first cut the underbrush from under the trees, and
also many of the vines or creepers, which looked very singular as
they hung down over our heads. Then we collected a great number
of large leaves, which are called by some tribes shayshayray and
guaygayrai, to roof our sheds with. After this we proceeded to cut a
number of small sticks, seven or eight feet long, and began to
construct our habitations. Then we cut branches of trees to shield us
from the wind, and collected a great quantity of firewood, for we
had made up our minds to keep ourselves warm. After we had
arranged and lighted the fires, our camp looked quite like a little
village. It was very romantic and beautiful. I had arranged my own
shelter very nicely; and it was first in the row. To be sure, my bed
was rather hard, being composed of sticks and leafy branches; while
for a pillow I had merely a piece of wood.
In the midst of our work, ten slaves of Njambai came, laden with
provisions, which the good fellow had sent after me. After doing a
hard day's work, I think we deserved to rest comfortably in the
evening. We began cooking our dinner; and a right good dinner it
was. My men had monkey and buffalo-meat; but I had a nice fat
fowl, which my friend Njambai had sent me.
Before dinner I warned my men to be honest, and keep their fingers
at home. They were good fellows, but I found that all savages will
steal. So I threatened to kill the first man I caught meddling with my
property, and told them I would shoot without mercy; "and then,"
said I, with great sternness, "when I have blown your brains out, I
will settle the matter with your king." To which Aboko coolly replied
that the settlement was not likely to do them any particular good.
Of course they all protested that they were honest; but I knew them
better than they knew themselves; I knew the effect of temptation
on them, poor fellows! and had more confidence in their faith that I
would kill the thief than I had in their good resolutions.
When this little matter was settled, they drew around the blazing
fire. By this time, the buffalo-meat suspended in a huge kettle over
the fire was cooked and ready to be eaten; the monkeys had been
roasted on charcoal; my fowl had been cooked; and before us was a
great pile of roasted plantain. We enjoyed a hearty meal together; I
eating off a plate, and using a fork, while the black fellows took
fresh leaves for plates, and used the "black man's fork," as they call
their five fingers. After dinner, they drank a large calabash-full of
palm wine that had been brought from Ngola; and then, to crown
their feast, with the greatest delight of all, I went to one of my
boxes, and, lifting the lid, while the shining black faces peered at me
with saucer-eyes of expectation, I took out a huge plug of Kentucky
tobacco. There was a wild hurrah of joy from them all. They shouted
that I was their friend; they loved only me; they would go with
nobody else; I was their good spirit; I was like one of themselves. I
distributed the tobacco among them; and in a few minutes all were
lying about the fire, or seated round it, with their pipes in their
mouths.
After making the fire burn brightly I, being tired, went and lay down,
as you see me in the picture. My blanket was the only article of
bedding I had; I wrapped this around me, and rested my head on
my wooden pillow, which I assure you was not of the softest kind. I
felt pleased to see my men so contented. Their wild stories of
hunting adventures, of witchcraft, and evil spirits well fitted the
rude, picturesque surroundings; and they lay there talking away, till,
at last, I was obliged to remind them that it was one o'clock, and
time to go to sleep, especially as some of us were to get up very
early and go hunting. Then all became silent, and soon we all fell
asleep, except the men appointed to keep the fires bright, on
account of the leopards, and also to watch that we might not be
surprised by some enemy.
A LEOPARD AND HER YOUNG ONE.
CHAPTER XVII.

AN UNSUCCESSFUL HUNT FOR ELEPHANTS—I TAKE AIM


AT A BUFFALO—A LEOPARD IN THE GRASS NEAR US—WE
SHOOT THE LEOPARD AND HER KITTEN—GREAT
REJOICING IN CAMP—WHO SHALL HAVE THE TAIL?—A
QUARREL OVER THE BRAINS—THE GUINEA HENS—THE
MONKEYS.

Early the next morning, Aboko and I got up. Aboko covered himself
with his war fetiches, and also with the fetiches that were to bring
good luck, and give him a steady hand. On the middle of his
forehead was a yellow spot made with clay. When he had finished
these preparations we started.
Our desire was to kill elephants. We saw plenty of tracks, and we
hunted all day long. In many places, to judge by the tracks, the
elephants had been only an hour or two before ourselves. But we
did not see a single elephant, and I killed only a few monkeys for my
men's dinner, as well as a few birds.
We were returning to the camp, rather down-hearted, when I heard
the cry of the grey male partridge, of which I have already spoken,
calling for his mates to come and perch on the tree he had chosen.
We turned back to get a shot, if possible, for they are fine eating.
We were just on the edge of the forest; and, as I pushed out into
Welcome to our website – the ideal destination for book lovers and
knowledge seekers. With a mission to inspire endlessly, we offer a
vast collection of books, ranging from classic literary works to
specialized publications, self-development books, and children's
literature. Each book is a new journey of discovery, expanding
knowledge and enriching the soul of the reade

Our website is not just a platform for buying books, but a bridge
connecting readers to the timeless values of culture and wisdom. With
an elegant, user-friendly interface and an intelligent search system,
we are committed to providing a quick and convenient shopping
experience. Additionally, our special promotions and home delivery
services ensure that you save time and fully enjoy the joy of reading.

Let us accompany you on the journey of exploring knowledge and


personal growth!

ebooknice.com

You might also like