-
-
Save so0k/e629004298a284d7653a6abc345c4bca to your computer and use it in GitHub Desktop.
$ docker run -it -w /go/src/k8s.io/ golang:1.8 bash.
root@64fe59077e2b:/go/src/k8s.io# git clone https://github.com/kubernetes/kops.git
Cloning into 'kops'...
remote: Counting objects: 143858, done.
remote: Compressing objects: 100% (83/83), done.
remote: Total 143858 (delta 42), reused 44 (delta 18), pack-reused 143752
Receiving objects: 100% (143858/143858), 154.71 MiB | 2.33 MiB/s, done.
Resolving deltas: 100% (81700/81700), done.
Checking connectivity... done.
Checking out files: 100% (30333/30333), done.
root@64fe59077e2b:/go/src/k8s.io# cd kops/
root@64fe59077e2b:/go/src/k8s.io/kops# git checkout 1.7.1
Note: checking out '1.7.1'
root@64fe59077e2b:/go/src/k8s.io/kops# make channels
go install -ldflags "-X k8s.io/kops.Version=1.7.1 " k8s.io/kops/channels/cmd/channels
root@64fe59077e2b:/go/src/k8s.io/kops# which channels
/go/bin/channels
root@64fe59077e2b:/go/src/k8s.io/kops# cd /go/bin
root@64fe59077e2b:/go/bin# zip -9 channels-linux-amd64.zip channels
adding: channels (deflated 77%)
root@64fe59077e2b:/go/bin# ls -lah
total 64M
drwxrwxrwx 1 root root 4.0K Nov 27 13:16 .
drwxrwxrwx 1 root root 4.0K Nov 27 13:11 ..
-rwxr-xr-x 1 root root 52M Nov 27 13:12 channels
-rw-r--r-- 1 root root 12M Nov 27 13:16 channels-linux-amd64.zip
How does channels keep track of deployed addons?
Review kube-system
namespace annotations
kubectl get ns kube-system -o json | jq .
{
"apiVersion": "v1",
"kind": "Namespace",
"metadata": {
"annotations": {
"addons.k8s.io/core.addons.k8s.io": "{\"version\":\"1.4.0\",\"channel\":\"s3://305788746247-bee02-kops-state-store/bee02-cluster.training.honestbee.com/addons/bootstrap-channel.yaml\"}",
"addons.k8s.io/dns-controller.addons.k8s.io": "{\"version\":\"1.7.1\",\"channel\":\"s3://305788746247-bee02-kops-state-store/bee02-cluster.training.honestbee.com/addons/bootstrap-channel.yaml\",\"id\":\"k8s-1.6\"}",
"addons.k8s.io/kube-dns.addons.k8s.io": "{\"version\":\"1.14.5\",\"channel\":\"s3://305788746247-bee02-kops-state-store/bee02-cluster.training.honestbee.com/addons/bootstrap-channel.yaml\",\"id\":\"k8s-1.6\"}",
"addons.k8s.io/kube-state-metrics.addons.k8s.io": "{\"version\":\"v1.1.0-rc.0\",\"channel\":\"beekeeper/addons.yaml\"}",
"addons.k8s.io/kubernetes-dashboard": "{\"version\":\"1.7.1\",\"channel\":\"kubernetes-dashboard\"}",
"addons.k8s.io/limit-range.addons.k8s.io": "{\"version\":\"1.5.0\",\"channel\":\"s3://305788746247-bee02-kops-state-store/bee02-cluster.training.honestbee.com/addons/bootstrap-channel.yaml\"}",
"addons.k8s.io/monitoring-standalone": "{\"version\":\"1.6.0\",\"channel\":\"monitoring-standalone\"}",
"addons.k8s.io/namespaces.honestbee.io": "{\"version\":\"1.1.2\",\"channel\":\"beekeeper/addons.yaml\"}",
"addons.k8s.io/storage-aws.addons.k8s.io": "{\"version\":\"1.6.0\",\"channel\":\"s3://305788746247-bee02-kops-state-store/bee02-cluster.training.honestbee.com/addons/bootstrap-channel.yaml\"}",
"addons.k8s.io/tiller.addons.k8s.io": "{\"version\":\"2.7.2\",\"channel\":\"beekeeper/addons.yaml\",\"id\":\"k8s-1.7\"}",
"kubectl.kubernetes.io/last-applied-configuration": "{\"apiVersion\":\"v1\",\"kind\":\"Namespace\",\"metadata\":{\"annotations\":{},\"name\":\"kube-system\",\"namespace\":\"\"}}\n"
},
...
}
Using jq
We can filter annotations down to those that contain addons
term and unwrap the json
embedded.
kubectl get ns kube-system -o json | \
jq '.metadata.annotations | with_entries(select(.value | contains("addons"))) | map_values(fromjson)'
Which returns
{
"addons.k8s.io/core.addons.k8s.io": {
"version": "1.4.0",
"channel": "s3://305788746247-bee02-kops-state-store/bee02-cluster.training.honestbee.com/addons/bootstrap-channel.yaml"
},
"addons.k8s.io/dns-controller.addons.k8s.io": {
"version": "1.7.1",
"channel": "s3://305788746247-bee02-kops-state-store/bee02-cluster.training.honestbee.com/addons/bootstrap-channel.yaml",
"id": "k8s-1.6"
},
"addons.k8s.io/kube-dns.addons.k8s.io": {
"version": "1.14.5",
"channel": "s3://305788746247-bee02-kops-state-store/bee02-cluster.training.honestbee.com/addons/bootstrap-channel.yaml",
"id": "k8s-1.6"
},
"addons.k8s.io/kube-state-metrics.addons.k8s.io": {
"version": "v1.1.0-rc.0",
"channel": "beekeeper/addons.yaml"
},
"addons.k8s.io/limit-range.addons.k8s.io": {
"version": "1.5.0",
"channel": "s3://305788746247-bee02-kops-state-store/bee02-cluster.training.honestbee.com/addons/bootstrap-channel.yaml"
},
"addons.k8s.io/namespaces.honestbee.io": {
"version": "1.1.2",
"channel": "beekeeper/addons.yaml"
},
"addons.k8s.io/storage-aws.addons.k8s.io": {
"version": "1.6.0",
"channel": "s3://305788746247-bee02-kops-state-store/bee02-cluster.training.honestbee.com/addons/bootstrap-channel.yaml"
},
"addons.k8s.io/tiller.addons.k8s.io": {
"version": "2.7.2",
"channel": "beekeeper/addons.yaml",
"id": "k8s-1.7"
}
}
or use this
kubectl get ns kube-system -o json \
| jq '.metadata.annotations | with_entries(select(.value | contains("addons"))) | map_values(fromjson | .version)'
{
"addons.k8s.io/core.addons.k8s.io": "1.4.0",
"addons.k8s.io/dns-controller.addons.k8s.io": "1.7.1",
"addons.k8s.io/kube-dns.addons.k8s.io": "1.14.5",
"addons.k8s.io/kube-state-metrics.addons.k8s.io": "v1.1.0-rc.0",
"addons.k8s.io/limit-range.addons.k8s.io": "1.5.0",
"addons.k8s.io/namespaces.honestbee.io": "1.1.2",
"addons.k8s.io/storage-aws.addons.k8s.io": "1.6.0",
"addons.k8s.io/tiller.addons.k8s.io": "2.7.2"
}
Create an AWS account and get a domain name follow the excelent kops on aws guides
(for Sydney use ap-southeast-2
)
easy DNS validation with Gsuite dig
export CLUSTER=staging
export DOMAIN=spawnhub
export NAME=${CLUSTER}.${DOMAIN}.com
export KOPS_STATE_STORE=s3://kubernetes-${DOMAIN}-com-state-store
export AWS_REGION=ap-southeast-2
export KEY_NAME=k8s-${CLUSTER}-${DOMAIN}
# make bucket (with location constraint)
aws s3 mb ${KOPS_STATE_STORE} --region ${AWS_REGION}
aws s3api put-bucket-versioning --bucket ${KOPS_STATE_STORE##*/} --versioning-configuration Status=Enabled
# aws ec2 describe-availability-zones --region ap-southeast-2
mkdir -p ~/.ssh/
aws --region ${AWS_REGION} ec2 create-key-pair --key-name ${KEY_NAME} --query 'KeyMaterial' --output text > ~/.ssh/${KEY_NAME}.pem
chmod 400 ~/.ssh/${KEY_NAME}.pem
ssh-add ~/.ssh/${KEY_NAME}.pem
ssh-keygen -y -f ~/.ssh/${KEY_NAME}.pem > ~/.ssh/${KEY_NAME}.pub
#potentially need --dns-zone if multiple zones match the domain name
kops create cluster \
--zones ap-southeast-2a \
--ssh-public-key ~/.ssh/${KEY_NAME}.pub \
--authorization RBAC
${NAME}
kops update cluster ${NAME} --yes # to actually create the cluster
# takes max 5 min..
kops validate cluster ${NAME}
# get dashboard - https://github.com/kubernetes/dashboard/releases
kubectl create -f https://raw.githubusercontent.com/kubernetes/dashboard/v1.6.3/src/deploy/kubernetes-dashboard.yaml
# alternatively - add DNS mapper? (not applied for this talk)
https://github.com/kubernetes/kops/blob/75718857b69756ac8374a1001363eadfa6f09a4f/addons/route53-mapper/README.md
# Ideally use something like kube-lego to use https with cog...
Install Helm's Tiller to cluster
helm init
nodeup
is the component that installs packages and sets up the OS, sufficiently for Kubelet In addition, nodeup installs:
Protokube
, which is a kops-specific component (in charge of etcd cluster mostly at the moment)
nodeup
creates manifests in /etc/kubernetes/manifests
, a directory the kubelet
is configured to monitor.
Traditionally, flannel was used to allocate and assign subnets for each node.
in Kops, the kubelet
tries to contact the API server and register its node. only when the API Server is up and allocates a PodCIDR
to the node, the actual Container Runtime will start.
in detail:
- when API server can be reached
kubelet
creates Node object representing itselfkube-controller-manager
assignsPodCIDR
kubelet
seesPodCIDR
assignment and configures local docker bridge (cbr0)- node will be marked as ready and
scheduler
will assign pods to the node kubelet
handles assigned pods
the kubelet
will set up the local bridge with the allocated CIDR
, only then the container runtime can start.
Prior to this, all core
containers run with hostNetwork=true
and can start without the bridge being available.
On Masters, API server listens on localhost
unsecured, controller manager and scheduler can thus connect through localhost without a token.
a dns-controller running in k8s will create DNS records with the cloud provider to allow discovery of the master nodes.
Protokube
:
- Discovers EBS volumes by doing an AWS query using labels
resource "aws_ebs_volume" "a-etcd-events-c01-honestbee-jp" {
availability_zone = "ap-northeast-1a"
size = 20
type = "gp2"
encrypted = false
tags = {
KubernetesCluster = "c01.honestbee.jp"
Name = "a.etcd-events.c01.honestbee.jp"
"k8s.io/etcd/events" = "a/a"
"k8s.io/role/master" = "1"
}
}
- Tries to safe_format_and_mount EBS volumes
- when a volume is mounted, write a manifest for etcd into
/etc/kubernetes/manifests
- configures DNS for the etcd nodes (can't use dns-controller as API requires etcd)
nodeup
https://kubeupv2.s3.amazonaws.com/kops/1.6.0/linux/amd64/nodeup
./nodeup --install-systemd-unit --conf=${INSTALL_DIR}/kube_env.yaml --v=8
Assets
kubelet
kubectl
cni
kops utils
protokube
Sample kube_env.yaml
Assets:
- 57afca200aa6cec74fcc3072cae12385014f59c0@https://storage.googleapis.com/kubernetes-release/release/v1.6.2/bin/linux/amd64/kubelet
- 984095cd0fe8a8172ab92e2ee0add49dfc46e0c2@https://storage.googleapis.com/kubernetes-release/release/v1.6.2/bin/linux/amd64/kubectl
- 1d9788b0f5420e1a219aad2cb8681823fc515e7c@https://storage.googleapis.com/kubernetes-release/network-plugins/cni-0799f5732f2a11b329d9e3d51b9c8f2e3759f2ff.tar.gz
- a821df4b965dbb119ed207c397b605a1fd99db3c@https://kubeupv2.s3.amazonaws.com/kops/1.6.0/linux/amd64/utils.tar.gz
ClusterName: c01.honestbee.jp
ConfigBase: s3://honestbee-kops-training-clusters-state/c01.honestbee.jp
InstanceGroupName: master-ap-northeast-1a
Tags:
- _automatic_upgrades
- _aws
- _kubernetes_master #nodes just drop this tag...
channels:
- s3://honestbee-kops-training-clusters-state/c01.honestbee.jp/addons/bootstrap-channel.yaml
protokubeImage:
hash: ca9f3a641d4130616f09403afbf5eed749633a86
name: protokube:1.6.0
source: https://kubeupv2.s3.amazonaws.com/kops/1.6.0/images/protokube.tar.gz
Provide simpler installation flow and sustainable cluster lifecycle upgrade/management.
- Self hosted should reduce the number of components required on the host.
- Reduces the number of files written to disk (less Config Mngmnt requirements)
- Introspection (kube system logs provide insights to kube components)
- Kubernetes itself is subject to upgrades via k8s API itself
- Easier HA
Dogfooding k8s will likely improve installation experience for other projects as well
- kubelet
- etcd
- apiserver
- scheduler / controller manager / proxy
- dns & addons
- providing 2-4 self-hosting since July 2016
- providing 1-4 self-hosting since Q1 2017
Temporary k8s control plane to control kubelet and spin up full blown control plane
Step 1 relies on System hosted kubelet
Step 2 relies on self-hosted kubelet with --exit-on-lock-contention
Step 3 system hosted has to watch for posix lock to ensure self-hosted stays alive
- control components pinned to control nodes
- LB for API server depends on off-cluster DNS/TLS/LB
- during hand-off, self-hosted components unsupervised and danger for crashes
- periodic snapshotting of pods manifests to local node manifest directory
(Any pod which contains the
checkpointer.alpha.coreos.com/checkpoint=true
annotation will be considered a viable "parent pod" which should be checkpointed.)
Note on static pod manifests (--pod-manifest-path
or --manifest-url
):
The major downside of using static Pods is that they are a special class of Pod.
While visible in the API server (as “mirror” Pods), they are read-only and cannot be controlled by it.
As kubelet itself uses a system hosted kublet (not self-hosted) through
kubelet-wrapper
, when an update is required - a node annotation is made which
is read by a long running daemonset which updates the kubelet-wrapper
config.
This allows kubelet version updates from the cluster API
stateless and self-hosted - managed through cluster API (set image version, update service label selectors)
Note: May cause temp downtime and may require fix depending on Kubernetes versioning policy and support for version skew between the control plane components
Progress is being made with integration of etcd-operator
into bootkube
...
- cluster version tied to bootkube version
- maintenance burden to keep bootkube version updated
- more moving parts and complexity increase chance of failure
How do other proposal rate against the above points:
- kubeadm also requires a release per k8s version
- kubelet pod API also adds additional complexity and doesn't cover hand-off as bootkube does
Ideally kubelet pod API replaces bootkube in the long run
If the tectonic_base_domain is set to kube.example.com
a Route 53 zone must exist for this domain and the AWS nameservers must be configured for the domain.
Based on kops DNS subdomain config.
In this scenario you want to contain all kubernetes records under a subdomain of a domain you host in Route53. This requires creating a second hosted zone in route53, and then setting up route delegation to the new zone.
In this example you own example.com and your records for Kubernetes would look like c01.tectonic.example.com
# Assuming a public domain for Cluster API ($DOMAIN is public zone)
ID=$(uuidgen)
export DOMAIN=example.com
export CLUSTER_DOMAIN=tectonic.${DOMAIN}
export CHILD_ID=$(aws route53 create-hosted-zone --name ${CLUSTER_DOMAIN} --caller-reference $ID --query "HostedZone.Id" --output text)
export PARENT_ID=$(aws route53 list-hosted-zones --query="HostedZones[?Name=='${DOMAIN}.' && Config.PrivateZone==\`false\`].Id" --output=text)
# create NS records for child zone in parent zone
aws route53 get-hosted-zone --id ${CHILD_ID} --query="DelegationSet. {Comment:'Create ${CLUSTER_DOMAIN} NS record in ${DOMAIN} domain',Changes:[{Action:'CREATE',ResourceRecordSet:{Name:'${CLUSTER_DOMAIN}',Type:'NS',TTL:\`300\`,ResourceRecords:NameServers[*].{Value:@}}}]}" > subdomain.json
aws route53 change-resource-record-sets --hosted-zone-id ${PARENT_ID} --change-batch file://subdomain.json
To provision Tectonic console Admin login:
curl -Lo bcrypt-tool.tar.gz https://github.com/coreos/bcrypt-tool/releases/download/v1.0.0/bcrypt-tool-v1.0.0-darwin-amd64.tar.gz
# sha512sum bcrypt-tool-v1.0.0-linux-amd64.tar.gz
tar -zxvf bcrypt-tool.tar.gz
./bcrypt-tool/bcrypt-tool
Read Tectonic with Terraform docs
Download tectonic release
curl -O https://releases.tectonic.com/tectonic-1.6.7-tectonic.1.tar.gz # download
tar -xzvf tectonic-1.6.7-tectonic.1.tar.gz # extract the tarball
cd tectonic
cluster c01.tectonic.example.com
export PATH=$PATH:$(pwd)/tectonic-installer/darwin
export TERRAFORM_CONFIG=$(pwd)/.terraformrc
# terraform init should be sufficient?
# config s3 backend and use terraform env?
terraform get platforms/aws
export CLUSTER=c01
mkdir -p build/${CLUSTER}
cp examples/terraform.tfvars.aws build/${CLUSTER}/terraform.tfvars
Review:
- tectonic_admin_email
- tectonic_admin_password_hash
- tectonic_aws_region
- tectonic_aws_ssh_key
- tectonic_base_domain
- tectonic_cluster_name
- tectonic_vanilla_k8s
- tectonic_worker_count
- tectonic_master_count
Plan and Apply
terraform plan -var-file=build/${CLUSTER}/terraform.tfvars -state=build/${CLUSTER}/terraform.tfstate platforms/aws
terraform apply -var-file=build/${CLUSTER}/terraform.tfvars -state=build/${CLUSTER}/terraform.tfstate platforms/aws
Note: Seems you can not provision 2 clusters from the same install dir, the generated/
dir is overwritten causing terraform plan no longer to work across the 2 clusters. Why? Known Issue
- Should learn to use
terraform env
- Should update the location of assets directory
Assets directory issue:
- the bootkube Terraform module is using the Terraform TLS Provider to generate self-signed certificates and stores everything in the generated directory:
resource "tls_private_key" "apiserver" {
algorithm = "RSA"
rsa_bits = "2048"
}
resource "local_file" "apiserver-key" {
content = "${tls_private_key.apiserver.private_key_pem}"
filename = "./generated/tls/apiserver.key"
}
- the bootkube Terraform module also generates the kubeconfig
data "template_file" "kubeconfig" {
template = "${file("${path.module}/resources/kubeconfig")}"
vars {
ca_cert = "${base64encode(var.ca_cert == "" ? join(" ", tls_self_signed_cert.kube-ca.*.cert_pem) : var.ca_cert)}"
kubelet_cert = "${base64encode(tls_locally_signed_cert.kubelet.cert_pem)}"
kubelet_key = "${base64encode(tls_private_key.kubelet.private_key_pem)}"
server = "${var.kube_apiserver_url}"
}
}
resource "local_file" "kubeconfig" {
content = "${data.template_file.kubeconfig.rendered}"
filename = "./generated/auth/kubeconfig"
}
...
- the aws/s3.tf module gets the output from aws/tectonic.tf which uses the Archive.data_archive Terraform resource:
data "archive_file" "assets" {
type = "zip"
source_dir = "./generated/"
# Because the archive_file provider is a data source, depends_on can't be
# used to guarantee that the tectonic/bootkube modules have generated
# all the assets on disk before trying to archive them. Instead, we use their
# ID outputs, that are only computed once the assets have actually been
# written to disk. We re-hash the IDs (or dedicated module outputs, like module.bootkube.content_hash)
# to make the filename shorter, since there is no security nor collision risk anyways.
#
# Additionally, data sources do not support managing any lifecycle whatsoever,
# and therefore, the archive is never deleted. To avoid cluttering the module
# folder, we write it in the TerraForm managed hidden folder `.terraform`.
output_path = "./.terraform/generated_${sha1("${module.tectonic.id} ${module.bootkube.id}")}.zip"
}
# Bootkube / Tectonic assets
resource "aws_s3_bucket_object" "tectonic-assets" {
bucket = "${aws_s3_bucket.tectonic.bucket}"
key = "assets.zip"
source = "${data.archive_file.assets.output_path}"
acl = "private"
# To be on par with the current Tectonic installer, we only do server-side
# encryption, using AES256. Eventually, we should start using KMS-based
# client-side encryption.
server_side_encryption = "AES256"
}
You can either import these into the new cluster state (to share secrets... which is a bad idea), or you can add the cluster name to the output directory of all assets (TLS /
- Ensure api endpoint resolves
dig +short c01-api.tectonic.honestbee.jp
-
Watch for external api ELB when instances come into service
or... to troubleshoot master
- get public ip and ssh -i ~/path/to/key core@
- on the first master node:
journalctl -u bootkube -f
journalctl -u kubelet -f
-
Monitor cluster services booting...
KUBECONFIG=generated/auth/kubeconfig kubectl get po --all-namespaces -w
If you are using Tectonic license (free for up to 10 nodes)
Ingress will exist for tectonic-console
and tectonic-identity
open https://${CLUSTER}.${CLUSTER_DOMAIN}
See CoreOS Instructions
Example LDAP set up using jumpcloud.com (for free - up to 10 users - need 1 user for ldap.service)
-
Create a user for
ldap.service
and give the user permission toBind and search Jumpcloud LDAP service
, also make sure to enableJumpcloud LDAP
in theDirectories
tab of this user -
Create the users in Jumpcloud and make sure to enable
Jumpcloud LDAP
inDirectories
tab of each user -
Create Group in Jumpcloud and make sure to enable
Jumpcloud LDAP
inDirectories
tab -
If you do not
create Linux Group
, Jumpcloud will expose the group as(objectClass=groupOfNames)
and you need to use the Distinguished Name (dn
) attribute of the user to match themember
attribute of the groupuserSearch: baseDN: 'ou=Users,o=<organization_id>,dc=jumpcloud,dc=com' filter: (objectClass=person) username: mail idAttr: uid emailAttr: mail nameAttr: cn groupSearch: baseDN: 'ou=Users,o=<organization_id>,dc=jumpcloud,dc=com' filter: (objectClass=groupOfNames) userAttr: DN groupAttr: member nameAttr: cn
-
If you do enable
create Linux Group
in jumpCloud, the group will exist as(objectClass=posixGroup)
as well and you can use theuid
attribute of the user to match thememberUid
attribute of the groupuserSearch: baseDN: 'ou=Users,o=<organization_id>,dc=jumpcloud,dc=com' filter: (objectClass=person) username: mail idAttr: uid emailAttr: mail nameAttr: cn groupSearch: baseDN: 'ou=Users,o=<organization_id>,dc=jumpcloud,dc=com' filter: (objectClass=posixGroup) userAttr: uid groupAttr: memberUid nameAttr: cn
-
In tectonic console, create a Cluster Role Binding for Cluster Role
admin
to Subject:group
and the name matching the posixGroup name
Tip: To troubleshoot the set up, download the OSX ldapsearch script or search ldap manually as follows (using TLS and port 636):
export ORG_ID="555..."
export LDAP_SERVICE_DN="uid=ldap.service,ou=Users,o=${ORG_ID},dc=jumpcloud,dc=com"
export LDAP_SERVICE_PASSWORD='...'
ldapsearch -H ldaps://ldap.jumpcloud.com:636 -x -b "ou=Users,o=${ORG_ID},dc=jumpcloud,dc=com" -D ${LDAP_SERVICE_DN} -w $LDAP_SERVICE_PASSWORD "(objectClass=person)"
ldapsearch -H ldaps://ldap.jumpcloud.com:636 -x -b "ou=Users,o=${ORG_ID},dc=jumpcloud,dc=com" -D ${LDAP_SERVICE_DN} -w $LDAP_SERVICE_PASSWORD "(objectClass=posixGroup)"
Enable GitHub authentication with Tectonic Identity ...
Download your cluster config file from console or keep using the kubelet config file...
export KUBECONFIG=generated/auth/kubeconfig
kubectl run --image=quay.io/coreos/example-app:v1.0 simple-deployment --port=80
po=$(kubectl get po -l run=simple-deployment -o name | head -n 1)
kubectl port-forward ${po##*/} 8080:80
open http://localhost:8080
expose service using ELB (old way)
KUBECONFIG=generated/auth/kubeconfig kubectl expose deploy simple-deployment --target-port=80 --type=LoadBalancer
Note tectonic out of the box deployments:
- container-linux-update-operator (deployment)
- container-linux-update-agent-ds (daemonset)
- heapster
- node-exporter (daemonset)
- pod-checkpointer
- kube-state-metrics
- prometheus-operator
- tectonic-console
- tectonic-identity
- tectonic-ingress-controller
- tectonic-stats-emitter
Vanilla:
- kube-controller-manager
- kube-dns
- kube-scheduler
- pod-checkpointer (makes snapshots of manifest to node /etc/kubernetes/manifests for fast recovery)
Missing nice to have (will need to configure to bootstrap by ourselves):
- container-linux-update-operator (Deployment)
- container-linux-update-agent-ds (deamonset)
- heapster (to run auto scalers?)
- kube-state-metrics (we can get from DataDog chart)
- no identity manager set up (need to set up oidc with google auth or dex for GitHub)
Other stuff we need to add (in any case):
- ALB ingress controller
- cluster-autoscaler
Default Tectonic RBAC roles:
- admin
- cluster-admin
- edit
- user
- view
- kube-state-metrics
- prometheus-k8s
- prometheus-operator
- extension-apiserver-authentication-reader
Tectonic
kubectl get roles,rolebindings --all-namespaces
NAMESPACE NAME AGE
kube-public roles/system:controller:bootstrap-signer 8h
kube-system roles/extension-apiserver-authentication-reader 8h
kube-system roles/system:controller:bootstrap-signer 8h
kube-system roles/system:controller:token-cleaner 8h
NAMESPACE NAME AGE
kube-public rolebindings/system:controller:bootstrap-signer 8h
kube-system rolebindings/system:controller:bootstrap-signer 8h
kube-system rolebindings/system:controller:token-cleaner 8h
kubectl get clusterroles,clusterrolebindings
NAME AGE
clusterroles/admin 8h
clusterroles/cluster-admin 8h
clusterroles/edit 8h
clusterroles/kube-state-metrics 8h
clusterroles/prometheus-k8s 8h
clusterroles/prometheus-operator 8h
clusterroles/system:auth-delegator 8h
clusterroles/system:basic-user 8h
clusterroles/system:controller:attachdetach-controller 8h
clusterroles/system:controller:certificate-controller 8h
clusterroles/system:controller:cronjob-controller 8h
clusterroles/system:controller:daemon-set-controller 8h
clusterroles/system:controller:deployment-controller 8h
clusterroles/system:controller:disruption-controller 8h
clusterroles/system:controller:endpoint-controller 8h
clusterroles/system:controller:generic-garbage-collector 8h
clusterroles/system:controller:horizontal-pod-autoscaler 8h
clusterroles/system:controller:job-controller 8h
clusterroles/system:controller:namespace-controller 8h
clusterroles/system:controller:node-controller 8h
clusterroles/system:controller:persistent-volume-binder 8h
clusterroles/system:controller:pod-garbage-collector 8h
clusterroles/system:controller:replicaset-controller 8h
clusterroles/system:controller:replication-controller 8h
clusterroles/system:controller:resourcequota-controller 8h
clusterroles/system:controller:route-controller 8h
clusterroles/system:controller:service-account-controller 8h
clusterroles/system:controller:service-controller 8h
clusterroles/system:controller:statefulset-controller 8h
clusterroles/system:controller:ttl-controller 8h
clusterroles/system:discovery 8h
clusterroles/system:heapster 8h
clusterroles/system:kube-aggregator 8h
clusterroles/system:kube-controller-manager 8h
clusterroles/system:kube-dns 8h
clusterroles/system:kube-scheduler 8h
clusterroles/system:node 8h
clusterroles/system:node-bootstrapper 8h
clusterroles/system:node-problem-detector 8h
clusterroles/system:node-proxier 8h
clusterroles/system:persistent-volume-provisioner 8h
clusterroles/user 8h
clusterroles/view 8h
NAME AGE
clusterrolebindings/admin-user 8h
clusterrolebindings/cluster-admin 8h
clusterrolebindings/devops 6h
clusterrolebindings/discovery 8h
clusterrolebindings/kube-state-metrics 8h
clusterrolebindings/prometheus-k8s 8h
clusterrolebindings/prometheus-operator 8h
clusterrolebindings/system:basic-user 8h
clusterrolebindings/system:controller:attachdetach-controller 8h
clusterrolebindings/system:controller:certificate-controller 8h
clusterrolebindings/system:controller:cronjob-controller 8h
clusterrolebindings/system:controller:daemon-set-controller 8h
clusterrolebindings/system:controller:deployment-controller 8h
clusterrolebindings/system:controller:disruption-controller 8h
clusterrolebindings/system:controller:endpoint-controller 8h
clusterrolebindings/system:controller:generic-garbage-collector 8h
clusterrolebindings/system:controller:horizontal-pod-autoscaler 8h
clusterrolebindings/system:controller:job-controller 8h
clusterrolebindings/system:controller:namespace-controller 8h
clusterrolebindings/system:controller:node-controller 8h
clusterrolebindings/system:controller:persistent-volume-binder 8h
clusterrolebindings/system:controller:pod-garbage-collector 8h
clusterrolebindings/system:controller:replicaset-controller 8h
clusterrolebindings/system:controller:replication-controller 8h
clusterrolebindings/system:controller:resourcequota-controller 8h
clusterrolebindings/system:controller:route-controller 8h
clusterrolebindings/system:controller:service-account-controller 8h
clusterrolebindings/system:controller:service-controller 8h
clusterrolebindings/system:controller:statefulset-controller 8h
clusterrolebindings/system:controller:ttl-controller 8h
clusterrolebindings/system:default-sa 8h
clusterrolebindings/system:discovery 8h
clusterrolebindings/system:kube-controller-manager 8h
clusterrolebindings/system:kube-dns 8h
clusterrolebindings/system:kube-scheduler 8h
clusterrolebindings/system:node 8h
clusterrolebindings/system:node-proxier 8h
Vanila k8s RBAC roles:
kubectl get roles,rolebindings --all-namespaces
NAMESPACE NAME AGE
kube-public roles/system:controller:bootstrap-signer 3h
kube-system roles/extension-apiserver-authentication-reader 3h
kube-system roles/system:controller:bootstrap-signer 3h
kube-system roles/system:controller:token-cleaner 3h
NAMESPACE NAME AGE
kube-public rolebindings/system:controller:bootstrap-signer 3h
kube-system rolebindings/system:controller:bootstrap-signer 3h
kube-system rolebindings/system:controller:token-cleaner 3h
kubectl get clusterroles,clusterrolebindings
NAME AGE
clusterroles/admin 3h
clusterroles/cluster-admin 3h
clusterroles/edit 3h
clusterroles/system:auth-delegator 3h
clusterroles/system:basic-user 3h
clusterroles/system:controller:attachdetach-controller 3h
clusterroles/system:controller:certificate-controller 3h
clusterroles/system:controller:cronjob-controller 3h
clusterroles/system:controller:daemon-set-controller 3h
clusterroles/system:controller:deployment-controller 3h
clusterroles/system:controller:disruption-controller 3h
clusterroles/system:controller:endpoint-controller 3h
clusterroles/system:controller:generic-garbage-collector 3h
clusterroles/system:controller:horizontal-pod-autoscaler 3h
clusterroles/system:controller:job-controller 3h
clusterroles/system:controller:namespace-controller 3h
clusterroles/system:controller:node-controller 3h
clusterroles/system:controller:persistent-volume-binder 3h
clusterroles/system:controller:pod-garbage-collector 3h
clusterroles/system:controller:replicaset-controller 3h
clusterroles/system:controller:replication-controller 3h
clusterroles/system:controller:resourcequota-controller 3h
clusterroles/system:controller:route-controller 3h
clusterroles/system:controller:service-account-controller 3h
clusterroles/system:controller:service-controller 3h
clusterroles/system:controller:statefulset-controller 3h
clusterroles/system:controller:ttl-controller 3h
clusterroles/system:discovery 3h
clusterroles/system:heapster 3h
clusterroles/system:kube-aggregator 3h
clusterroles/system:kube-controller-manager 3h
clusterroles/system:kube-dns 3h
clusterroles/system:kube-scheduler 3h
clusterroles/system:node 3h
clusterroles/system:node-bootstrapper 3h
clusterroles/system:node-problem-detector 3h
clusterroles/system:node-proxier 3h
clusterroles/system:persistent-volume-provisioner 3h
clusterroles/view 3h
NAME AGE
clusterrolebindings/cluster-admin 3h
clusterrolebindings/kubernetes-dashboard 7m
clusterrolebindings/system:basic-user 3h
clusterrolebindings/system:controller:attachdetach-controller 3h
clusterrolebindings/system:controller:certificate-controller 3h
clusterrolebindings/system:controller:cronjob-controller 3h
clusterrolebindings/system:controller:daemon-set-controller 3h
clusterrolebindings/system:controller:deployment-controller 3h
clusterrolebindings/system:controller:disruption-controller 3h
clusterrolebindings/system:controller:endpoint-controller 3h
clusterrolebindings/system:controller:generic-garbage-collector 3h
clusterrolebindings/system:controller:horizontal-pod-autoscaler 3h
clusterrolebindings/system:controller:job-controller 3h
clusterrolebindings/system:controller:namespace-controller 3h
clusterrolebindings/system:controller:node-controller 3h
clusterrolebindings/system:controller:persistent-volume-binder 3h
clusterrolebindings/system:controller:pod-garbage-collector 3h
clusterrolebindings/system:controller:replicaset-controller 3h
clusterrolebindings/system:controller:replication-controller 3h
clusterrolebindings/system:controller:resourcequota-controller 3h
clusterrolebindings/system:controller:route-controller 3h
clusterrolebindings/system:controller:service-account-controller 3h
clusterrolebindings/system:controller:service-controller 3h
clusterrolebindings/system:controller:statefulset-controller 3h
clusterrolebindings/system:controller:ttl-controller 3h
clusterrolebindings/system:default-sa 3h
clusterrolebindings/system:discovery 3h
clusterrolebindings/system:kube-controller-manager 3h
clusterrolebindings/system:kube-dns 3h
clusterrolebindings/system:kube-scheduler 3h
clusterrolebindings/system:node 3h
clusterrolebindings/system:node-proxier 3h
in Vanilla:
kubectl create -f https://raw.githubusercontent.com/kubernetes/dashboard/v1.6.1/src/deploy/kubernetes-dashboard.yaml
Dashboard vs Tectonic console:
- dashboard does not provide an interface for Roles and RoleBindings (will just need to manage those as code and through terminal)
Kops default roles:
kubectl get roles --all-namespaces
NAMESPACE NAME AGE
kube-public system:controller:bootstrap-signer 4m
kube-system extension-apiserver-authentication-reader 4m
kube-system system:controller:bootstrap-signer 4m
kube-system system:controller:token-cleaner 4m
Summary of commands to provision cluster
export DOMAIN=honestbee.jp
export CLUSTER_DOMAIN=tectonic.${DOMAIN}
export INSTALLER_PATH=$(pwd)/tectonic-installer/darwin/installer
export PATH=$PATH:$(pwd)/tectonic-installer/darwin
sed "s|<PATH_TO_INSTALLER>|$INSTALLER_PATH|g" terraformrc.example > .terraformrc
export TERRAFORM_CONFIG=$(pwd)/.terraformrc
terraform get platforms/aws
export AWS_ACCESS_KEY_ID=
export AWS_SECRET_ACCESS_KEY=
export AWS_REGION=ap-northeast-1
export CLUSTER=c01
mkdir -p build/${CLUSTER}
cp examples/terraform.tfvars.aws build/${CLUSTER}/terraform.tfvars
#edit terraform.tfvars
code .
export KEY_NAME=c01-tectonic-honestbee-jp
aws --region ${AWS_REGION} ec2 create-key-pair --key-name ${KEY_NAME} --query 'KeyMaterial' --output text > ~/.ssh/${KEY_NAME}.pem
chmod 400 ~/.ssh/${KEY_NAME}.pem
ssh-add ~/.ssh/${KEY_NAME}.pem
ssh-keygen -y -f ~/.ssh/${KEY_NAME}.pem > ~/.ssh/${KEY_NAME}.pub
echo "~/.ssh/${KEY_NAME}.pub"
echo "${KEY_NAME}" | pbcopy #paste in terraform.tfvars
terraform plan -var-file=build/${CLUSTER}/terraform.tfvars -state=build/${CLUSTER}/terraform.tfstate platforms/aws
terraform apply -var-file=build/${CLUSTER}/terraform.tfvars -state=build/${CLUSTER}/terraform.tfstate platforms/aws
dig +short c01-api.tectonic.honestbee.jp
KUBECONFIG=generated/auth/kubeconfig kubectl get no
Notes on Tectonic bootstrapping process:
- If you have multiple masters, only 1 of them will be the bootkube master, the others won't run bootkube!
- Vanilla k8s is creating Load balancer for tectonic console, which is never used in vanilla deploys
- Tectonic runs AWS scripts using
quay.io/coreos/awscli
(which has vulnerabilities at the time of writing) - the AWS Scripts on the masters:
-
get instance id from metadata service:
curl http://169.254.169.254/latest/meta-data/instance-id
-
get autoscaling group name:
autoscaling describe-auto-scaling-instances --region="ap-northeast-1" --instance-ids=...
-
loop until ASG is at desired capacity:
aws autoscaling describe-auto-scaling-groups --region="$REGION" --auto-scaling-group-names=... jq ".AutoScalingGroups[0] .DesiredCapacity" == jq ".AutoScalingGroups[0] .Instances | sort_by(.InstanceId) | .[].InstanceId" | wc -l
-
Test if current instanceid ==
jq ".AutoScalingGroups[0] .Instances | sort_by(.InstanceId) | .[].InstanceId"
| head -n1
.Only if current instanceid is the first in the ASG, it will run bootkube...
-
Kops
Practice Disaster Recovery
Before destroying, get rid of ELBs
export KUBECONFIG=generated/auth/kubeconfig
kubectl get services --all-namespaces -o json | jq -r ".items[] | select(.spec.type==\"LoadBalancer\") | .metadata.name"
terraform plan --destroy -var-file=build/${CLUSTER}/terraform.tfvars -state=build/${CLUSTER}/terraform.tfstate platforms/aws
terraform destroy -var-file=build/${CLUSTER}/terraform.tfvars -state=build/${CLUSTER}/terraform.tfstate platforms/aws
Notice a few hiccups on resource management, could be terraform issue.