Instala Kubernetes y Docker en entorno sin Internet

Instala Kubernetes y Docker en entorno sin Internet

Pasos para preparar un entorno para instalar Kubernetes y Docker en Red Hat y CentOS donde no es posible acceder a internet

Descargar e instalar Docker

YUM realiza la resolución de dependencias al instalar, actualizar y eliminar paquetes de software, pero si no tiene acceso a Internet, debe instalar los paquetes con el comando rpm. Muchas veces es muy difícil, o tedioso preparar la instalación del software Linux cuando no se tiene acceso a Internet a los repositorios o tienes repositorios privados, la dificultad radica en que los RPMs pueden tener muchas dependencias y es necesario descargar cada una de estas dependencias una por una, a veces en un enfoque de prueba y error, que es muy dificíl, como caminar en la oscuridad.

El escebario asume que vamos a instalar Kubernetes y Docker en un servidor Red Hat 7 sin conectividad a Internet, si necesitas instalar otro software, el proceso será similar, 1) descargar los paquetes en su PC local, 2) cargar archivos TAR en el servidor sin conexión y 3) instalar paquetes. Necesitas RHEL con acceso a Internet, pero para que sea mucho más sencillo, para este proceso vamos a utilizar un contenedor Centos como "puente" para descargar paquetes y todas sus dependencias. Si eres un usuario de Windows, también puedes utilizar WSL (te va a encantar!), puedes ver como configurarlo en nuestro artículo: "Linux for Windows Users" (en inglés).

Consulta las otras opciones que hemos preparado para instalar Kubernetes y Docker sin conexión (en inglés):

Si te interesa que genere más contenido en español, déjamelo saber en los comentarios o escribeme aquí.

Ejecuta el contenedor Centos montando un volumen en su host/PC Docker, luego, esa ruta se usará para empaquetar todos los archivos que se cargarán en el servidor sin acceso a Internet.

Este proceso se ejecutó y probó usando WSL en la PC con acceso a Internet, el directorio utilizado para guardar los archivos en el ejemplo es: your_rpm_dir --> /c/Temp/deleteme

Descarga Docker (PC con Internet/Docker host)

Si te interesa un ambiente para probar esta instalacion sin instalar nada, déjamelo saber aqui. Revisa nuestros laboratorios aquí.

docker pull centos:centos7
docker run -d --name centos -v <your_rpm_dir>:/var/rpm_dir centos:centos7
docker exec -it centos /bin/bash

# Ahora en el contenedor de Docker, ejecuta los siguientes comandos
# Configura YUM para descargar los paquetes correctamente
yum install -y yum-utils
# instala el repo para Docker
yum-config-manager --add-repo \
https://download.docker.com/linux/centos/docker-ce.repo
# Descarga los archivos necesarios para instalar Docker
yumdownloader --assumeyes --destdir=/var/rpm_dir/yum --resolve yum-utils
yumdownloader --assumeyes --destdir=/var/rpm_dir/dm --resolve device-mapper-persistent-data
yumdownloader --assumeyes --destdir=/var/rpm_dir/lvm2 --resolve lvm2
yumdownloader --assumeyes --destdir=/var/rpm_dir/docker-ce --resolve docker-ce
yumdownloader --assumeyes --destdir=/var/rpm_dir/se --resolve container-selinux

Descarga Kubernetes (PC online/Docker host)

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

# Descarga las utilerias de Kubernetes (en este ejemplo, la version 1.21 de K8s):
yumdownloader --assumeyes --destdir=/var/rpm_dir/kube --resolve yum-utils kubeadm-1.21.* kubelet-1.21.* kubectl-1.21.* ebtables

Copia los archivos de Docker de la PC con Internet al servidor sin acceso a Internet

tar -czvf d4r-k8s.tar.gz /var/rpm_dir
mv d4r-k8s.tar.gz /var/rpm_dir/
# Conectate a tu servidor sin internet (VPN)
ssh root@10.100.10.44
mkdir /var/rpm_dir
# En el host de Docker
cd /c/Temp/deleteme
scp d4r-k8s.tar.gz root@10.100.10.44:/var/rpm_dir
tar -xzvf d4r-k8s.tar.gz -C /

Instala Docker (Servidor offline)

# Instala utilerias de yum (offline machine)
yum install -y --cacheonly --disablerepo=* /var/rpm_dir/yum/*.rpm
# instala los drivers de Docker:
yum install -y --cacheonly --disablerepo=* /var/rpm_dir/dm/*.rpm
yum install -y --cacheonly --disablerepo=* /var/rpm_dir/lvm2/*.rpm
# instala container-selinux:
yum install -y --cacheonly --disablerepo=* /var/rpm_dir/se/*.rpm
# instala Docker:
yum install -y --cacheonly --disablerepo=* /var/rpm_dir/docker-ce/*.rpm
# habilita y arranca el servicio de Docker:
systemctl enable docker
systemctl start docker
# Verifica que todo está bien con Docker:
systemctl status docker
docker version

🚀 Docker está listo!

Instala Kubernetes (offline machine)

yum install -y --cacheonly --disablerepo=* /var/rpm_dir/kube/*.rpm
# ejecuta kubeadm, para ver la lista de las imagenes que necesitamos:
kubeadm config images list

Se debe mostrar la lista de imagenes de Docker requeridas, probablemente con un error, porque el servidor no tiene Internet:

W1103 10:05:20.147419     653 version.go:102] could not fetch a Kubernetes version from the internet: unable to get URL "https://dl.k8s.io/release/stable-1.txt": Get "https://dl.k8s.io/release/stable-1.txt": dial tcp: lookup dl.k8s.io on 192.168.22.2:53: server misbehaving
W1103 10:05:20.147489     653 version.go:103] falling back to the local client version: v1.21.3
W1103 10:05:20.147648     653 configset.go:348] WARNING: kubeadm cannot validate component configs for API groups [kubelet.config.k8s.io kubeproxy.config.k8s.io]
k8s.gcr.io/kube-apiserver:v1.21.3
k8s.gcr.io/kube-controller-manager:v1.21.3
k8s.gcr.io/kube-scheduler:v1.21.3
k8s.gcr.io/kube-proxy:v1.21.3
k8s.gcr.io/pause:3.2
k8s.gcr.io/etcd:3.4.13-0
k8s.gcr.io/coredns:1.7.0

Descarga e Instala las imágenes de Kubernetes

En tu host de Docker (tu PC), descarga y guarda las imágenes requeridas de Kubernetes

mkdir docker-images
cd docker-images
# descarga las imagenes
docker pull k8s.gcr.io/kube-apiserver:v1.21.3
docker pull k8s.gcr.io/kube-controller-manager:v1.21.3
docker pull k8s.gcr.io/kube-scheduler:v1.21.3
docker pull k8s.gcr.io/kube-proxy:v1.21.3
docker pull k8s.gcr.io/pause:3.2
docker pull k8s.gcr.io/etcd:3.4.13-0
docker pull k8s.gcr.io/coredns:1.7.0
# guarda las imagenes en archivos TAR
docker save k8s.gcr.io/kube-apiserver:v1.21.3 > kube-apiserver_v1.21.3.tar
docker save k8s.gcr.io/kube-controller-manager:v1.21.3 > kube-controller-manager_v1.21.3.tar
docker save k8s.gcr.io/kube-scheduler:v1.21.3 > kube-scheduler_v1.21.3.tar
docker save k8s.gcr.io/kube-proxy:v1.21.3 > kube-proxy_v1.21.3.tar
docker save k8s.gcr.io/pause:3.2 > pause_3.2.tar
docker save k8s.gcr.io/etcd:3.4.13-0 > etcd_3.4.13-0.tar
docker save k8s.gcr.io/coredns:1.7.0  > coredns_1.7.0.tar
# Empaqueta todos los archivos TAR
tar -czvf docker-images.tar.gz 
# copia al servidor sin Internet
scp docker-images.tar.gz root@10.100.10.44:/var/rpm_dir

Carga las imágenes de Kubernetes (en el servidor sin Internet)

# extrae las imágenes
mkdir -p /var/rpm_dir/docker-images
cd /var/rpm_dir/
tar -xzvf docker-images.tar.gz -C /var/rpm_dir/docker-images
# desempaqueta y carga las imagenes
for x in *.tar; do docker load < $x && echo "cargado del archivo $x"; done;

Descarga las imágenes de networking (PC online)

Flannel es una red virtual que proporciona una subred a cada host/nodo de Kubernetes para su uso en tiempo de ejecución de los contenedores. ¿No te gusta Flannel? Consultar otras opciones aquí.

# descarga el descriptor yaml
wget https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
# revisa la version de la imagen requerida para flannel
grep image kube-flannel.yml
# Descarga y guarda la imagen requerida (del comando anterior) - en este ejemplo la version 0.20.1
docker pull docker.io/rancher/mirrored-flannelcni-flannel:v0.20.1
docker save docker.io/rancher/mirrored-flannelcni-flannel:v0.20.1 > flannel_v0.20.1.tar
# comprime los archivos para carga mas facil
tar -czvf flannel_v0.20.1.tar.gz flannel_v0.20.1.tar kube-flannel.yml
#gzip -v flannel_v0.20.1.tar
# copia al servidor sin Internet
scp flannel_v0.20.1.tar.gz root@10.100.10.44:/var/rpm_dir

Instala los archivos de red para Kubernetes (servidor offline)

cd /var/rpm_dir/
# desempaqueta la imagen de red:
tar -xzvf flannel_v0.20.1.tar.gz
#gzip -d flannel_v0.20.1.tar.gz
docker load < flannel_v0.20.1.tar

Descarga las imagenes de Nginx (PC online)

Utilizado para permitir el acceso a los contenedores, es la puerta de entrada del mundo exterior al cluster de Kubernetes.

mkdir nginx
cd nginx
# descarga el descriptor yaml:
wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/ingress-nginx-3.8.0/deploy/static/provider/baremetal/deploy.yaml
# descarga y guarda las imagenes:
docker pull k8s.gcr.io/ingress-nginx/controller:v0.41.0
docker pull docker.io/jettech/kube-webhook-certgen:v1.5.0
docker save k8s.gcr.io/ingress-nginx/controller:v0.41.0 > nginx-controller_v0.41.0.tar
docker save docker.io/jettech/kube-webhook-certgen:v1.5.0 > kube-webhook-certgen_v1.5.0.tar
cd ..
tar -czvf nginx.tar.gz nginx
scp nginx.tar.gz root@10.100.10.44:/var/rpm_dir

Carga las imagenes de Ingress-Nginx (servidor offline)

cd /var/rpm_dir/
tar -xzvf nginx.tar.gz -C /var/rpm_dir
cd nginx
# desempaqueta y carga las imagenes
for x in *.tar; do docker load < $x && echo "loaded from file $x"; done;

Despliega el cluster de Kubernetes (servidor offline)

hostnamectl set-hostname 'sdk8s-master'
# deshabilita 'swap' para la sesion actual
swapoff -a
# Asegura que SELinux esta en modo permisivo
setenforce 0
sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config
cat <<EOF >  /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
sysctl --system
# En caso de que no tengas un DNS para los FQDN de tu nuevo cluster, entonces actualiza el archivo /etc/hosts en nodos maestro y 'workers'
192.168.22.8    sdk8s-master
192.168.22.40   sdworker-node1
192.168.22.50   sdworker-node2
# La configuracion de /etc/host la debes hacer en todos los nodos de tu cluster antes de continuar
# habilita el servidio: kubelet
systemctl enable kubelet.service
kubectl version
kubeadm init --pod-network-cidr=10.244.0.0/16 --kubernetes-version=v1.21.3 > ~/kubeadm.init.log
# IMPORTANTE: el archivo ~/kubeadm.init.log generado en la ejecucion del 'init' incuye el token requerido para unir los 'worker nodes' al cluster

mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

# verifica que los nodos esten corriendo
kubectl get nodes
# Configura kubectl para gestionar el cluster
grep -q "KUBECONFIG" ~/.bashrc || {
    echo 'export KUBECONFIG=/etc/kubernetes/admin.conf' >> ~/.bashrc
    . ~/.bashrc
}

cd /var/rpm_dir/
# inicia la red de Flannel en el nodo de control (Control Plane)
kubectl apply -f kube-flannel.yml
# El cluster no programa pods en el nodo de control por motivos de seguridad de forma predeterminada.
# En mi caso, estoy implementando un solo nodo, entonces, ejecutar este comando elimina el 'taint' node-role.kubernetes.io/master 
# de cualquier nodo que lo tenga, para que el programador pueda programar pods en todas partes:
kubectl taint nodes --all node-role.kubernetes.io/master-

Agrega los 'worker nodes' al cluster

# Busca el comando 'join' guardado en el archivo del paso anterior: ~/kubeadm.init.log
kubeadm join 192.168.22.8:6443 --token 49gfys.l4obg3x8flxyc0fr \
    --discovery-token-ca-cert-hash sha256:479203ed42d2884d950ddb81874ea11667788805511b297f3a32c7958fd7fd27
# en la maquina del nodo de Control, verifica los nodos:
kubectl get nodes

Referencias:

Backup / logs

Haz clic para ver los logs
W1104 18:18:31.401054     851 configset.go:348] WARNING: kubeadm cannot validate component configs for API groups [kubelet.config.k8s.io kubeproxy.config.k8s.io]
[init] Using Kubernetes version: v1.21.3
[preflight] Running pre-flight checks
        [WARNING IsDockerSystemdCheck]: detected "cgroupfs" as the Docker cgroup driver. The recommended driver is "systemd". Please follow the guide at https://kubernetes.io/docs/setup/cri/
        [WARNING Service-Kubelet]: kubelet service is not enabled, please run 'systemctl enable kubelet.service'
[preflight] Pulling images required for setting up a Kubernetes cluster
[preflight] This might take a minute or two, depending on the speed of your internet connection
[preflight] You can also perform this action in beforehand using 'kubeadm config images pull'
[certs] Using certificateDir folder "/etc/kubernetes/pki"
[certs] Generating "ca" certificate and key
[certs] Generating "apiserver" certificate and key
[certs] apiserver serving cert is signed for DNS names [kubernetes kubernetes.default kubernetes.default.svc kubernetes.default.svc.cluster.local sdk8s-master] and IPs [10.96.0.1 192.168.22.8]
[certs] Generating "apiserver-kubelet-client" certificate and key
[certs] Generating "front-proxy-ca" certificate and key
[certs] Generating "front-proxy-client" certificate and key
[certs] Generating "etcd/ca" certificate and key
[certs] Generating "etcd/server" certificate and key
[certs] etcd/server serving cert is signed for DNS names [localhost sdk8s-master] and IPs [192.168.22.8 127.0.0.1 ::1]
[certs] Generating "etcd/peer" certificate and key
[certs] etcd/peer serving cert is signed for DNS names [localhost sdk8s-master] and IPs [192.168.22.8 127.0.0.1 ::1]
[certs] Generating "etcd/healthcheck-client" certificate and key
[certs] Generating "apiserver-etcd-client" certificate and key
[certs] Generating "sa" key and public key
[kubeconfig] Using kubeconfig folder "/etc/kubernetes"
[kubeconfig] Writing "admin.conf" kubeconfig file
[kubeconfig] Writing "kubelet.conf" kubeconfig file
[kubeconfig] Writing "controller-manager.conf" kubeconfig file
[kubeconfig] Writing "scheduler.conf" kubeconfig file
[kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env"
[kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml"
[kubelet-start] Starting the kubelet
[control-plane] Using manifest folder "/etc/kubernetes/manifests"
[control-plane] Creating static Pod manifest for "kube-apiserver"
[control-plane] Creating static Pod manifest for "kube-controller-manager"
[control-plane] Creating static Pod manifest for "kube-scheduler"
[etcd] Creating static Pod manifest for local etcd in "/etc/kubernetes/manifests"
[wait-control-plane] Waiting for the kubelet to boot up the control plane as static Pods from directory "/etc/kubernetes/manifests". This can take up to 4m0s
[apiclient] All control plane components are healthy after 9.502572 seconds
[upload-config] Storing the configuration used in ConfigMap "kubeadm-config" in the "kube-system" Namespace
[kubelet] Creating a ConfigMap "kubelet-config-1.19" in namespace kube-system with the configuration for the kubelets in the cluster
[upload-certs] Skipping phase. Please see --upload-certs
[mark-control-plane] Marking the node sdk8s-master as control-plane by adding the label "node-role.kubernetes.io/master=''"
[mark-control-plane] Marking the node sdk8s-master as control-plane by adding the taints [node-role.kubernetes.io/master:NoSchedule]
[bootstrap-token] Using token: 49gfys.l4obg3x8flxyc0fr
[bootstrap-token] Configuring bootstrap tokens, cluster-info ConfigMap, RBAC Roles
[bootstrap-token] configured RBAC rules to allow Node Bootstrap tokens to get nodes
[bootstrap-token] configured RBAC rules to allow Node Bootstrap tokens to post CSRs in order for nodes to get long term certificate credentials
[bootstrap-token] configured RBAC rules to allow the csrapprover controller automatically approve CSRs from a Node Bootstrap Token
[bootstrap-token] configured RBAC rules to allow certificate rotation for all node client certificates in the cluster
[bootstrap-token] Creating the "cluster-info" ConfigMap in the "kube-public" namespace
[kubelet-finalize] Updating "/etc/kubernetes/kubelet.conf" to point to a rotatable kubelet client certificate and key
[addons] Applied essential addon: CoreDNS
[addons] Applied essential addon: kube-proxy

Your Kubernetes control-plane has initialized successfully!

To start using your cluster, you need to run the following as a regular user:

  mkdir -p $HOME/.kube
  sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
  sudo chown $(id -u):$(id -g) $HOME/.kube/config

You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
  https://kubernetes.io/docs/concepts/cluster-administration/addons/

Then you can join any number of worker nodes by running the following on each as root:

kubeadm join 192.168.22.8:6443 --token 49gfys.l4obg3x8flxyc0fr \
    --discovery-token-ca-cert-hash sha256:479203ed42d2884d950ddb81874ea11667788805511b297f3a32c7958fd7fd27

Los rebeldes son disruptores: quieren cambiar las cosas y aportar nuevos conocimientos y posibilidades. ✊🏼

Únete a la comunidad "La Rebelion" aquí para recibir actualizaciones e información sobre la causa, lecciones interactivas de Kubernetes disponible, o regístrate en helmee beta.

¡Comparte lo que piensas y mejoras con nosotros!

Contáctame con confianza! 😉