The biggest bombshell news in tech recently was that RedHat are being bought by IBM. And in one of the WhatsApp groups I’m in, someone posted this:
Tag Archives: Linux
GitHub
My personal @github repos are now migrated to @gitlab.
As for why I chose to do this?
http://www.tuxmachines.org/node/112706 and http://techrights.org/2018/06/17/microsoft-patent-cybermobbing/ for starters…
New Ubuntu Quirks
So, I install Ubuntu 17 clean on my laptop after the issues I had with drivers and immediately found out that gksu was not installed.
Installed that and tried to
gksudo nautilus
That failed and found out that Wayland had replaced the default of Xorg. Found an old Xauthority file from my backups and copied that back, which allowed me to get the popup window back for my gksu, but I couldn’t click it to enter the password :(
Then I found this article:
https://www.linuxuprising.com/2018/04/gksu-removed-from-ubuntu-heres.html
Which tells me I need to use the admin:/// file prefix instead to open something up as admin. Guess I’ll give it a go later.
Upgrading Ubuntu (fun! ¬_¬)
Spent several hours trying to upgrade my Ubuntu installation from 15 up to the latest 17. The upgrade didn’t fail, but I did see a few error messages, and now I have applications failing to start for various reasons, including the settings applet; and when I install or use my nvidia drivers, ubuntu doesn’t start up properly until I do
apt-get purge nvidia*
But removing all the nvidia stuff causes it to fallback to nouveau which for the most part works, but not exactly good for any linux gaming.
Looks like it’s going to be a full-reinstall job to make sure everything is clean :(
Tunnelling to Kubernetes Nodes & Pods via a Bastion
A quick note to remind myself (and other people) how to tunnel to a node (or pod) in Kubernetes via the bastion server
rm ~/.ssh/known_hosts #Needed if you keep scaling the bastion up/down
BASTION=bastion.{cluster-domain}
DEST=$1
ssh -o StrictHostKeyChecking=no -o ProxyCommand='ssh -o StrictHostKeyChecking=no -W %h:%p admin@bastion.{cluster-domain}' admin@$DEST
Run like this:
bash ./tunnelK8s.sh NODE_IP
Example:
bash ./tunnelK8s.sh 10.10.10.100 #Assuming 10.10.10.100 is the node you want to connect to.
You can extend this by using this to ssh into a pod, assuming the pod has an SSH server on it.
BASTION=bastion.${cluster domain name}
NODE=$1
NODEPORT=$2
PODUSER=$3
ssh -o ProxyCommand="ssh -W %h:%p admin@$BASTION" admin@$NODE ssh -tto StrictHostKeyChecking=no $PODUSER@localhost -p $NODEPORT
So if you have service listening on port 32000 on node 10.10.10.100 that expects a login user of "poduser", you would do this:
bash ./tunnelPod.sh 10.10.10.100 32000 poduser
If you have to pass a password you can install sshpass on the node, then use that (be aware of security risk though – this is not an ideal solution)
ssh -o ProxyCommand="ssh -W %h:%p admin@$BASTION" admin@$NODE sshpass -p ${password} ssh -tto StrictHostKeyChecking=no $PODUSER@localhost -p $NODEPORT
Caveat though — you will have to make sure that your node security group allows your bastion security group to talk to the nodes on the additional ports. By default, the only port that the bastions are able to talk to the node security groups on is SSH (22) only.
How to using S3 as a RWM/NFS-like store in Kubernetes
Let’s assume you have an application that runs happily on its own and is stateless. No problem. You deploy it onto Kubernetes and it works fine. You kill the pod and it respins, happily continuing where it left off.
Let’s add three replicas to the group. That also is fine, since its stateless.
Let’s now change that so that the application is now stateful and requires storage of where it is in between runs. So you pre-provision a disk using EBS and hook that up into the pods, and convert the deployment to a stateful set. Great, it still works fine. All three will pick up where they left off.
Now, what if we wanted to share the same state between the replicas?
For example, what if these three replicas were frontend boxes to a website? Having three different disks is a bad idea unless you can guarantee they will all have the same content. Even if you can, there’s guaranteed to be a case where one or more of the boxes will be either behind or ahead of the other boxes, and consequently have a case where one or more of the boxes will serve the wrong version of content.
There are several options for shared storage, NFS is the most logical but requires you to pre-provision a disk that will be used and also to either have an NFS server outside the cluster or create an NFS pod within the cluster. Also, you will likely over-provision your disk here (100GB when you only need 20GB for example)
Another alternative is EFS, which is Amazon’s NFS storage, where you mount an NFS and only pay for the amount of storage you use. However, even when creating a filesystem in a public subnet, you get a private IP which is useless if you are not DirectConnected into the VPC.
Another option is S3, but how do you use that short of using “s3 sync” repeatedly?
One answer is through the use of s3fs and sshfs
We use s3fs to mount the bucket into a pod (or pods), then we can use those mounts via sshfs as an NFS-like configuration.
The downside to this setup is the fact it will be slower than locally mounted disks.
So here’s the yaml for the s3fs pods (change values within {…} where applicable) — details at Docker Hub here: https://hub.docker.com/r/blenderfox/s3fs/
(and yes, I could convert the environment variables into secrets and reference those, and I might do a follow up article for that)
---
kind: Deployment
apiVersion: extensions/v1beta1
metadata:
name: s3fs
namespace: default
labels:
k8s-app: s3fs
annotations: {}
spec:
replicas: 1
selector:
matchLabels:
k8s-app: s3fs
template:
metadata:
name: s3fs
labels:
k8s-app: s3fs
spec:
containers:
- name: s3fs
image: blenderfox/s3fs
env:
- name: S3_BUCKET
value: {...}
- name: S3_REGION
value: {...}
- name: AWSACCESSKEYID
value: {...}
- name: AWSSECRETACCESSKEY
value: {...}
- name: REMOTEKEY
value: {...}
- name: BUCKETUSERPASSWORD
value: {...}
resources: {}
imagePullPolicy: Always
securityContext:
privileged: true
restartPolicy: Always
terminationGracePeriodSeconds: 30
dnsPolicy: ClusterFirst
securityContext: {}
schedulerName: default-scheduler
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 25%
maxSurge: 25%
revisionHistoryLimit: 10
progressDeadlineSeconds: 600
---
kind: Service
apiVersion: v1
metadata:
name: s3-service
annotations:
external-dns.alpha.kubernetes.io/hostname: {hostnamehere}
service.beta.kubernetes.io/aws-load-balancer-connection-idle-timeout: "3600"
labels:
name: s3-service
spec:
ports:
- protocol: TCP
name: ssh
port: 22
targetPort: 22
selector:
k8s-app: s3fs
type: LoadBalancer
sessionAffinity: None
externalTrafficPolicy: Cluster
This will create a service and a pod
If you have external DNS enabled, the hostname will be added to Route 53.
SSH into the service and verify you can access the bucket mount
ssh bucketuser@dns-name ls -l /mnt/bucket/
(This should give you the listing of the bucket and also should have user:group set on the directory as “bucketuser”)
You should also be able to rsync into the bucket using this
rsync -rvhP /source/path bucketuser@dns-name:/mnt/bucket/
Or sshfs using a similar method
sshfs bucketuser@dns-name:/mnt/bucket/ /path/to/local/mountpoint
Edit the connection timeout annotation if needed
Now, if you set up a pod that has three replicas and all three sshfs to the same service, you essentially have an NFS-like storage.
Single Point of Failure: The LKML [The Register]
You are always lectured about making backups of your systems, even more so when you are running archives from a very active mailing list. ^_^
https://www.theregister.co.uk/2018/01/14/linux_kernel_mailing_list_archives_will_return_soon/
Guide to creating a Kubernetes Cluster in existing subnets & VPC on AWS with kops
This article is a guide on how to setup a Kubernetes cluster in AWS using kops and plugging it into your own subnets and VPC. We attempt to minimise the external IPs used in this method.
Export your AWS API keys into environment variables
export AWS_ACCESS_KEY_ID='YOUR_KEY' export AWS_SECRET_ACCESS_KEY='YOUR_ACCESS_KEY' export CLUSTER_NAME="my-cluster-name" export VPC="vpc-xxxxxx" export K8SSTATE="s3-k8sstate"</pre>
Create the cluster (you can change some of these switches to match your requirements. I would suggest only using one worker node and one master node to begin with and then increase them once you have confirmed the config is good. The more workers and master nodes you have, the longer it will take to run a rolling-update.
kops create cluster --cloud aws --name $CLUSTER_NAME --state s3://$K8SSTATE --node-count 1 --zones eu-west-1a,eu-west-1b,eu-west-1c --node-size t2.micro --master-size t2.micro --master-zoneseu-west-1a,eu-west-1b,eu-west-1c --ssh-public-key ~/.ssh/id_rsa.pub --topology=private --networking=weave --associate-public-ip=false --vpc $VPC
Important note: There must be an ODD number of master zones. If you tell kops to use an even number zones for master, it will complain.
If you want to use additional security groups, don’t add them yet — add them after you have confirmed the cluster is working.
Internal IPs: You must have a VPN connection into your VPC or you will not be able to ssh into the instances. The alternative is to use the bastion functionality using the --bastion flag with the create command. Then doing this:
ssh -i ~/.ssh/id_rsa -o ProxyCommand='ssh -W %h:%p admin@bastion.$CLUSTER_NAME' admin@INTERNAL_MASTER_IP
However, if you do this method, you MUST then use public IP addressing on the api load balancer, as you will not be able to do kops validate otherwise.
Edit the cluster
kops edit cluster $CLUSTER_NAME --state=s3://$K8SSTATE
Make the following changes:
If you have a VPN connection into the VPC, change spec.api.loadBalancer.type to “Internal“, otherwise, leave it as “Public”
Change spec.subnets to match your private subnets. To use existing private subnets, they should also include the id of the subnet and match the CIDR range, e.g.:
subnets: - cidr: 10.10.10.0/23 id: subnet-xxxxxxx name: eu-west-1a type: Private zone: eu-west-1a</pre>
The utility subnet is where the Bastion hosts will be placed, and these should be in a public subnet, since they will be the inbound route into the cluster from the internet.
If you need to change or add specific IAM permissions, add them under spec.additionalPolicies like this to add additional policies to the node IAM policy (apologies about the formatting. WordPress is doing something weird to it.)
additionalPolicies:
node: |
[
{
"Effect": "Allow",
"Action": ["dynamodb:*"],
"Resource": ["*"]
},
{
"Effect": "Allow",
"Action": ["es:*"],
"Resource": ["*"]
}
]
Edit the bastion, nodes, and master configs (MASTER_REGION is the zone where you placed the master. If you are running a multi-region master config, you’ll have to do this for each region)
kops edit ig master-{MASTER_REGION} --name=$CLUSTER_NAME --state s3://$K8SSTATE
kops edit ig nodes --name=$CLUSTER_NAME --state s3://$K8SSTATE
kops edit ig bastions --name=$CLUSTER_NAME --state s3://$K8SSTATE
Check and make any updates.
If you want a mixture of instance types (e.g. t2.mediums and r3.larges), you’ll need to separate these using new instance groups ($SUBNETS is the subnets where you want the nodes to appear — for example, you can provide a list “eu-west-2a,eu-west-2b)
kops create ig anothernodegroup --state s3://$K8SSTATE --subnets $SUBNETS
You can later delete this with
kops delete ig anothernodegroup --state s3://$K8SSTATE
If you want to use spot prices, add this under the spec section (x.xx is the price you want to bid):
maxPrice: "x.xx"
Check the instance size and count if you want to change them (I would recommend not changing the node count just yet)
If you want to add tags to the instances (for example for billing), add something like this to the spec section:
cloudLabels: Billing: product-team</pre>
If you want to run some script(s) at node startup (cloud-init), add them to spec.additionalUserData:
spec:
additionalUserData:
- name: myscript.sh
type: text/x-shellscript
content: |
#!/bin/sh
echo "Hello World. The time is now $(date -R)!" | tee /root/output.txt
Apply the update:
kops update cluster $CLUSTER_NAME --state s3://$K8SSTATE --yes
Wait for DNS to propagate and then validate
kops validate cluster --state s3://$K8SSTATE
Once the cluster returns ready, apply the Kubernetes dashboard
kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/master/src/deploy/alternative/kubernetes-dashboard.yaml
Access the dashboard via
https://api.$CLUSTER_NAME/api/v1/namespaces/kube-system/services/kubernetes-dashboard/proxy/
also try:
https://api.$CLUSTER_NAME/api/v1/namespaces/kube-system/services/https:kubernetes-dashboard:/proxy/
If the first doesn’t work
(ignore the cert error)
Username is “admin” and the password is found from your local ~/.kube/config
Add the External DNS update to allow you to give friendly names to your externally-exposed services rather than the horrible elb names.
See here: https://github.com/kubernetes-incubator/external-dns/blob/master/docs/tutorials/aws.md
(You can apply the yaml directly onto the cluster via the dashboard. Make sure you change the filter to match your domain or subdomain. )
Note that if you use this, you’ll need to change the node IAM policy on the cluster config as the default IAM policy won’t allow the External DNS container to modify Route 53 entries, and also annotate (use kubectl annotate $service_name key:value) your service with text such as:
external-dns.alpha.kubernetes.io/hostname: $SERVICE_NAME.$CLUSTERNAME
And also you might need this annotation, to make the ELB internal rather than public – otherwise Kubernetes will complain “Error creating load balancer (will retry): Failed to ensure load balancer for service namespace/service: could not find any suitable subnets for creating the ELB”
service.beta.kubernetes.io/aws-load-balancer-internal: 0.0.0.0/0
(Optional) Add the Cockpit pod to your cluster as described here
http://cockpit-project.org/guide/133/feature-kubernetes.html
It will allow you to visually see a topology of your cluster at a cluster and also provides some management features too. For example, here’s my cluster. It contains 5 nodes (1 master, 4 workers and is running 4 services (Kubernetes, external-dns, cockpit, and dashboard). Cockpit creates a replication controller so it knows about the changes.

Add any additional security groups by adding this under the spec section of the node/master/bastions config, then do a rolling-update (you might need to use the --force switch), do this as soon as you can after creating and verifying the cluster updates work.
additionalSecurityGroups: - sg-xxxxxxxx - sg-xxxxxxxx
If the cluster breaks after this (i.e. the nodes haven’t shown up on the master), reboot the server (don’t terminate, use the reboot option from the AWS console), and see if that helps. If it still doesn’t show up, there’s something wrong with the security groups attached — i.e. they’re conflicting somehow with the Kubernetes access. Remove those groups and then do another rolling-update but use both the --force and --cloudonly switches to force a “dirty” respin.
If the cluster comes up good, then you can change the node counts on the configs and apply the update.
Note that if you change the node count and then apply the update, the cluster attempts to make the update without rolling-update. For example, if you change the node count from 1 to 3, the cluster attempts to bring up the 2 additional nodes.
Other things you can look at:
Kompose – which converts a docker-compose configuration into Kubernetes resources
Finally, have fun!
Massive Intel Chip Security Flaw Threatens Computers
An Intel flaw that has been sitting hidden for a decade has finally surfaced.
Being on the chip rather than the OS, it doesn’t affect a single OS — with Linux, Windows and MacOS being mentioned in this article.
Tinkering with Kubernetes and AWS
This article just goes through my tinkering with Kubernetes on AWS.
Create a new S3 bucket to store the state of your Kubernetes clusters
aws s3 mb s3://k8sstate --region eu-west-2
Verify
aws s3 ls
Create a Route 53 hosted zone. I’m creating k8stest.blenderfox.uk
aws route53 create-hosted-zone --name k8stest.blenderfox.uk \ --caller-reference $(uuidgen)
dig the nameservers for the hosted zone you created
dig NS k8stest.blenderfox.uk
If your internet connection already has DNS setup to the hosted zone, you’ll see the nameservers in the output:
;; QUESTION SECTION: ;k8stest.blenderfox.uk. IN NS ;; ANSWER SECTION: k8stest.blenderfox.uk. 172800 IN NS ns-1353.awsdns-41.org. k8stest.blenderfox.uk. 172800 IN NS ns-1816.awsdns-35.co.uk. k8stest.blenderfox.uk. 172800 IN NS ns-404.awsdns-50.com. k8stest.blenderfox.uk. 172800 IN NS ns-644.awsdns-16.net.
Export your AWS credentials as environment variables (I’ve found Kubernetes doesn’t reliably pick up the credentials from the aws cli especially if you have multiple profiles
export AWS_ACCESS_KEY_ID='your key here' export AWS_SECRET_ACCESS_KEY='your secret access key here'
You can also add it to a bash script and source it.
Create the cluster using kops. Note that the master zones must have an odd count (1, 3, etc.) since eu-west-2 only has two zones (a and b), I have to have only one zone here
kops create cluster --cloud aws --name cluster.k8stest.blenderfox.uk \ --state s3://k8sstate --node-count 3 --zones eu-west-2a,eu-west-2b \ --node-size m4.large --master-size m4.large \ --master-zones eu-west-2a \ --ssh-public-key ~/.ssh/id_rsa.pub \ --master-volume-size 50 \ --node-volume-size 50 \ --topology private
You can also add the --kubernetes-version switch to specifically pick a Kubernetes version to include in the cluster. Recognised versions are shown at
https://github.com/kubernetes/kops/blob/master/channels/stable
TL;DL: Bands are:
- >=1.4.0 and <1.5.0
- >=1.5.0 and <1.6.0
- >=1.6.0 and <1.7.0
- >=1.7.0
Each with their own Debian image.
Assuming the create completed successfully, update the cluster so it pushes the update out to your cloud
kops update cluster cluster.k8stest.blenderfox.uk --yes \ --state s3://k8sstate
While the cluster starts up, all the new records will be set up with placeholder IPs.

NOTE: Kubernetes needs an externally resolvable DNS name. Basically, you need to be able to create a hosted zone on a domain you control. You can’t use Kops on a domain you can’t control, even if you hack the resolver config.
The cluster can take a while to come up. Use
kops validate cluster --state s3://k8sstate
To check the cluster state.
When ready, you’ll see something like this:
Using cluster from kubectl context: cluster.k8stest.blenderfox.co.uk Validating cluster cluster.k8stest.blenderfox.co.uk INSTANCE GROUPS NAME ROLE MACHINETYPE MIN MAX SUBNETS master-eu-west-2a Master m4.large 1 1 eu-west-2a nodes Node m4.large 3 3 eu-west-2a,eu-west-2b NODE STATUS NAME ROLE READY ip-172-20-35-51.eu-west-2.compute.internal master True ip-172-20-49-10.eu-west-2.compute.internal node True ip-172-20-72-100.eu-west-2.compute.internal node True ip-172-20-91-236.eu-west-2.compute.internal node True Your cluster cluster.k8stest.blenderfox.co.uk is ready
Now you can start interacting with the cluster. First thing is to deploy the Kubernetes dashboard
$ kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/master/src/deploy/alternative/kubernetes-dashboard.yaml serviceaccount "kubernetes-dashboard" created role "kubernetes-dashboard-minimal" created rolebinding "kubernetes-dashboard-minimal" created deployment "kubernetes-dashboard" created service "kubernetes-dashboard" created
Now setup a proxy to the api
$ kubectl proxy Starting to serve on 127.0.0.1:8001
Next, access
http://localhost:8001/ui
To get the dashboard
Now let’s create a job to deploy on to the cluster.




You must be logged in to post a comment.