https://www.raspberrypi.org/blog/docker-comes-to-raspberry-pi/
Instalamos Raspbian. Tarda unos 5 minutos https://www.raspberrypi.org/downloads/raspbian/
xz --decompress 2023-05-03-raspios-bullseye-arm64-lite.img.xz
dd if=2023-05-03-raspios-bullseye-arm64-lite.img of=/dev/mmcblk0
Esto nos crea dos particiones en la tarjeta:
bootfs rootfs
Modificamos la tarjeta para poder acceder sin monitor:
En la partición rootfs, ponemos IP fija cambiando el fichero añadiendo al final:
rootfs/etc/dhcpcd.conf
interface eth0 static ip_address=192.168.69.1/24 static routers=192.168.69.1 static domain_name_servers=192.168.69.1
Habilitamos ssh dejando un fichero en la partición boot que se llame ssh (da igual el contenido o si está vacio)
touch bootfs/ssh
A partir de la versión bulleyes tenemos que crear otro usuario para poder acceder:
Crear el fichero en boot llamado userconf con el contenido:
vim bootfs/userconf
username:encrypted_password
Por ejemplo, para ruth:odin sacamos la password:
echo 'odin' | openssl passwd -6 -stdin $6$S3pAIx36rcMzDYsK$vzl8eX.2k07Rbje9nJ4zsFQdieKw8Wg296javxQ.VW7SdknBlk03vFKh0eI8i4VGwPxWHiJCJNnCd7E72Sh8c0
Y sería:
echo 'ruth:$6$S3pAIx36rcMzDYsK$vzl8eX.2k07Rbje9nJ4zsFQdieKw8Wg296javxQ.VW7SdknBlk03vFKh0eI8i4VGwPxWHiJCJNnCd7E72Sh8c0' > bootfs/userconf
Modificamos la memoria SWAP que está a 100 y la ponemos a 1024:
rootfs/etc/dphys-swapfile
CONF_SWAPSIZE=1024
Deshabilitamos IPV6
https://sleeplessbeastie.eu/2022/07/20/how-to-disable-ipv6-on-raspberry-pi-4/
ip -br a
lo UNKNOWN 127.0.0.1/8 ::1/128 eth0 UP 172.16.1.101/16 fe80::14b8:2700:4354:ec24/64 wlan0 DOWN
echo net.ipv6.conf.all.disable_ipv6=1 | sudo tee /etc/sysctl.d/disable-ipv6.conf
Grabamos cambios:
sudo sysctl --system
Esto para gurb pero no me convence
Añadimos en la línea del fichero
/boot/cmdline.txt
Que tiene que ser algo así:
dwc_otg.lpm_enable=0 console=serial0,115200 console=tty1 root=PARTUUID=ee25660b-02 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait quiet init=/usr/lib/raspi-config/init_resize.sh
El siguiente parámetro
ipv6.disable=1
Ya podemos acceder por ssh
Nos conectamos y seguimos modificando
Con raspi-config, modificamos:
-Hostname
2. Network Options N1 Hostname
-Expandimos FileSystem (ya viene hecho):
7 Advanced Options A1 Expand Filesystem
-Cambiamos arranque a consola (no hace falta con lite)
3 Boot Options B1 Desktop / CLI B1 Console
-Cambiadmos pais Wifi:
4 Localisation Options I4 Change Wi-fi Country ES Spain
https://www.raspberrypi.org/documentation/configuration/wireless/wireless-cli.md
El primer nodo se conectará a una red wifi y dará internet al resto.
Escanemos las redes:
iwlist wlan0 scan
Añadimos la red y la contraseña al final del fichero
/etc/wpa_supplicant/wpa_supplicant.conf
p2p_disabled=1 network={ ssid="mi_red_wifi" psk="***************" }
Probamos de conectarnos a mano:
wpa_supplicant -B -i wlan0 -c /etc/wpa_supplicant/wpa_supplicant.conf
Reiniciamos el servicio:
wpa_cli -i wlan0 reconfigure
Podemos poner mas de una red en el fichero wpa_supplicant.conf y las seleccionamos con esta herramienta interactiva:
wpa_cli
list_networks select_network 1
Para el primer nodo le tenemos que quitar el default gw de la red 192.168.69.x. Editamos el fichero:
/etc/dhcpcd.conf
Y quitamos la línea:
static routers=192.168.69.1
Para compartir internet:
wlan0: red con internet
eth0: red interna por cable eth0 entre raspberris 192.168.69.1, 192.168.69.2 y 192.168.69.3
Permitimos reenvio entre interfaces editando /etc/sysctl.conf:
net.ipv4.ip_forward = 1
Lo añadimos en caliente
sysctl -p
Añadimos reglas iptables
iptables -A FORWARD -o wlan0 -i eth0 -m conntrack --ctstate NEW -j ACCEPT iptables -A FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT iptables -t nat -A POSTROUTING -o wlan0 -j MASQUERADE
Lo hacemos persistente Hay dos formas, guardar las reglas de iptables, no me convence porque puede haber mas y no se si se sobreescriben:
iptables-save > /etc/iptables.ipv4.nat
Añadimos antes del exit 0 en /etc/rc.local
iptables-restore < /etc/iptables.ipv4.nat
Debe quedar mas o menos así:
_IP=$(hostname -I) || true if [ "$_IP" ]; then printf "My IP address is %s\n" "$_IP" fi iptables-restore < /etc/iptables.ipv4.nat exit 0
La segunda es poner los 3 comandos de iptables en /etc/rc.local antes del exit 0
Instalamos dnsmasq para que funcione el DNS:
apt-get install dnsmasq
Para poner una entrada, las añadimos en el fichero
/etc/dnsmasq.conf
Al final ponemos:
address=/jenkins.rpicluster.com/192.168.69.2
Cada vez que añadamos una tenemos que reinicar el servicio:
systemctl restart dnsmasq
https://www.raspberrypi.org/documentation/configuration/wireless/access-point.md
El tercer nodo hará de Punto de acceso para que otros portátiles se conecten al clúster
apt-get install dnsmasq hostapd
systemctl stop dnsmasq sudo systemctl stop hostapd
/etc/dhcpcd.conf
interface wlan0 static ip_address=192.168.4.1/24
service dhcpcd restart
mv /etc/dnsmasq.conf /etc/dnsmasq.conf.orig
/etc/dnsmasq.conf
interface=wlan0 dhcp-range=192.168.4.2,192.168.4.20,255.255.255.0,24h
/etc/hostapd/hostapd.conf
interface=wlan0 driver=nl80211 ssid=raspicluster hw_mode=g channel=7 wmm_enabled=0 macaddr_acl=0 auth_algs=1 ignore_broadcast_ssid=0 wpa=2 wpa_passphrase=clusterraspi wpa_key_mgmt=WPA-PSK wpa_pairwise=TKIP rsn_pairwise=CCMP
/etc/default/hostapd DAEMON_CONF="/etc/hostapd/hostapd.conf"
Reiniciamos servicios:
systemctl start hostapd systemctl start dnsmasq
Si da un error:
Failed to start hostapd.service: Unit hostapd.service is masked.
Hacemos esto:
sudo systemctl unmask hostapd sudo systemctl enable hostapd sudo systemctl start hostapd
Al arrancar el servidor, arranca el servicio de hostapd pero no el AP. Pero si reiniciamos el servicio después de que arranque el servidor si que arranca el AP. Por lo tanto vamos a asegurarnos que el servicio hostapd arranca el útimo: Modificamos la seccion [Unit] del fichero
/usr/lib/systemd/system/hostapd.service
After=network.target network-online.target Wants=network-online.target
Tiene que quedar algo así:
[Unit] Description=Access point and authentication server for Wi-Fi and Ethernet Documentation=man:hostapd(8) After=network.target network-online.target Wants=network-online.target
Ahora hacemos que enruten las dos redes:
/etc/sysctl.conf net.ipv4.ip_forward=1
Para que aplique hay que reiniciar o lanzar:
sysctl -p
También añadir iptables. Para hacerlo persistente lo añadimos justo antes del exit 0 en
/etc/rc.local
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
Vemos si funciona:
# iwconfig wlan0 IEEE 802.11 Mode:Master Tx-Power=31 dBm Retry short limit:7 RTS thr:off Fragment thr:off Power Management:on
Podemos grabar logs añadiendo en:
/etc/default/hostapd
DAEMON_OPTS="-dd -t -f /var/log/hostapd.log" `-dd` -> "more logging" `-t` -> include timestamps `-f <path>` -> tells hostapd to log your data to `<path>`
Al arrancar los docker, usar:
-e TZ=Europe/Madrid
Instalamos Docker
curl -sSL https://get.docker.com | sh
Añadimos el usuario pi al grupo docker
usermod -aG docker ruth
Para que los docker resuelvan bien dnsmasq y que conecte con docker registry hay que añadir:
/etc/docker/daemon.json
{ "dns": [ "192.168.69.1", "8.8.8.8", "8.8.4.4" ], "insecure-registries": ["docker.raspi"] }
sudo service docker restart
Ponemos el puerto 80 porque el registry lo haremos inseguro para no tener que crear certificados:
docker pull registry:2 docker run -d -p 80:5000 --restart=always --name registry registry:2
Creamos una imagen, fichero Dockerfile, por ejemplo una simple con git:
FROM debian RUN apt-get update && \ apt-get install -y git CMD bash
Creamos la imagen:
docker build -t docker.raspi/git .
La subimos a nuestro Registry:
docker push docker.raspi/git
Ahora si vamos a otro nodo, la podemos descargar:
docker run -ti docker.raspi/git
docker run -ti resin/rpi-raspbian:latest cat /etc/os-release PRETTY_NAME="Raspbian GNU/Linux 8 (jessie)"
docker run -ti arm32v6/alpine:3.5
Apache:
docker run -ti -p 8080:80 hypriot/rpi-busybox-httpd
Si accedemos a 192.168.1.201:8080 nos sale web de apache
Ponemos las siguientes IPs:
raspiswarm1: 192.168.1.201 raspiswarm2: 192.168.1.202 raspiswarm3: 192.168.1.203
Iniciamos swarm en el nodo1:
docker swarm init
Para añadir otros nodos nos indica:
docker swarm join \ --token SWMTKN-1-0kn5tua6jptohuvohoh5v46vb75qscdz7b35hjecynl94xne40-520qqlthfm2bhukhqpj352sxi \ 192.168.1.201:2377
Los añadimos y nos dice:
This node joined a swarm as a worker.
Ejecutamos un servicio:
docker service create --name apache --replicas=2 -p 8080:80 hypriot/rpi-busybox-httpd
Si hacemos un docker ps vemos que lo ha levantado en la 1 y la 2, pero es accesible desde las 3 ips y va balanceando. Para parar el servicio:
docker service rm apache
Podemos crearlo mapeando una unidad local para ver que balancea, por ejemplo:
docker service create --name apache --replicas=3 -p 8080:80 --mount type=bind,src=/raspi/www,dst=/www hypriot/rpi-busybox-httpd
Si creamos un /raspi/www/index.html diferente para cada servidor, veremos como balancea
Tenemos que deshabilitar swap
dphys-swapfile swapoff dphys-swapfile uninstall update-rc.d dphys-swapfile remove
Modificamos:
/boot/cmdline.txt
cgroup_enable=memory
Instalamos Docker:
curl -sSL get.docker.com | sh && sudo usermod pi -aG docker
curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add - && \ echo "deb http://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kubernetes.list && \ sudo apt-get update -q && \ sudo apt-get install -qy kubeadm
Inicializamos el clúster. Ponemos el rango de IPs por si tenemos varios, en este caso wlan0 que sale a internet y eth0 que es la red local:
kubeadm init --apiserver-advertise-address=192.168.69.1
Cuando acaba da lo siguiente:
Your Kubernetes master 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/ You can now join any number of machines by running the following on each node as root: kubeadm join 192.168.69.1:6443 --token 08607b.fqzo9x9lh7fhp40r --discovery-token-ca-cert-hash sha256:3df520e18e42608c133b01af692b8881f6834319751e461c5deb8534a2055466
Ejecutamos esos comandos con el usuario pi.
Miramos el estado de los nodos:
kubectl get nodes NAME STATUS ROLES AGE VERSION kubernetes1 NotReady master 8m v1.10.2
Pone not ready porque falta configurar la red. El pod de dns se queda pendiente
kubectl get pods --all-namespaces NAMESPACE NAME READY STATUS RESTARTS AGE kube-system etcd-kubernetes1 1/1 Running 0 2m kube-system kube-apiserver-kubernetes1 1/1 Running 0 2m kube-system kube-controller-manager-kubernetes1 1/1 Running 0 1m kube-system kube-dns-686d6fb9c-dwtmh 0/3 Pending 0 2m kube-system kube-proxy-j9tmc 1/1 Running 0 2m kube-system kube-scheduler-kubernetes1 1/1 Running 0 2m
Lo podemos ver en los logs:
sudo journalctl -r -u kubelet May 02 23:46:39 kubernetes1 kubelet[16196]: E0502 23:46:39.401514 16196 kubelet.go:2125] Container runtime network not ready: NetworkReady=false rea May 02 23:46:39 kubernetes1 kubelet[16196]: W0502 23:46:39.401016 16196 cni.go:171] Unable to update cni config: No networks found in /etc/cni/net.d
Creamos la RED:
kubectl apply -f "https://cloud.weave.works/k8s/net?k8s-version=$(kubectl version | base64 | tr -d '\n')" serviceaccount "weave-net" created clusterrole.rbac.authorization.k8s.io "weave-net" created clusterrolebinding.rbac.authorization.k8s.io "weave-net" created role.rbac.authorization.k8s.io "weave-net" created rolebinding.rbac.authorization.k8s.io "weave-net" created daemonset.extensions "weave-net" created
Ahora vemos que ya están todos arrancados
kubectl get pods --all-namespaces NAMESPACE NAME READY STATUS RESTARTS AGE kube-system etcd-kubernetes1 1/1 Running 0 6m kube-system kube-apiserver-kubernetes1 1/1 Running 0 6m kube-system kube-controller-manager-kubernetes1 1/1 Running 0 5m kube-system kube-dns-686d6fb9c-dwtmh 3/3 Running 0 6m kube-system kube-proxy-j9tmc 1/1 Running 0 6m kube-system kube-scheduler-kubernetes1 1/1 Running 0 6m kube-system weave-net-59r4p 2/2 Running 0 1m
Y ya aparece bien en el listado de nodos:
kubectl get nodes NAME STATUS ROLES AGE VERSION kubernetes1 Ready master 8m v1.10.2
Añadimos un nodo al cluster:
kubeadm join 192.168.69.1:6443 --token 08607b.fqzo9x9lh7fhp40r --discovery-token-ca-cert-hash sha256:3df520e18e42608c133b01af692b8881f6834319751e461c5deb8534a2055466
This node has joined the cluster: * Certificate signing request was sent to master and a response was received. * The Kubelet was informed of the new secure connection details. Run 'kubectl get nodes' on the master to see this node join the cluster.
Desde el master miramos los nodos:
pi@kubernetes1:~ $ kubectl get nodes NAME STATUS ROLES AGE VERSION kubernetes1 Ready master 45m v1.10.2 kubernetes2 NotReady <none> 3m v1.10.2
Aparece NotReady porque hay que comentar la red cni en los otros nodos. Comentamos la línea que pone KUBELET_NETWORK_ARGS /etc/systemd/system/kubelet.service.d/10-kubeadm.conf
#Environment=“KUBELET_NETWORK_ARGS=–network-plugin=cni –cni-conf-dir=/etc/cni/net.d –cni-bin-dir=/opt/cni/bin”
Instalamos Dashboard:
echo -n 'apiVersion: rbac.authorization.k8s.io/v1beta1 kind: ClusterRoleBinding metadata: name: kubernetes-dashboard labels: k8s-app: kubernetes-dashboard roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: cluster-admin subjects: - kind: ServiceAccount name: kubernetes-dashboard namespace: kube-system' | kubectl apply -f -
Se crea el servicio:
clusterrolebinding.rbac.authorization.k8s.io "kubernetes-dashboard" created
No he probado:
$ kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/master/src/deploy/alternative/kubernetes-dashboard-arm.yaml
Hay que probar este:
pi@kubernetes1:~ $ kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/master/src/deploy/alternative/kubernetes-dashboard-arm.yaml serviceaccount "kubernetes-dashboard" created role.rbac.authorization.k8s.io "kubernetes-dashboard-minimal" created rolebinding.rbac.authorization.k8s.io "kubernetes-dashboard-minimal" created deployment.apps "kubernetes-dashboard" created service "kubernetes-dashboard" created
Para ver donde se está ejecutando:
# kubectl -n kube-system get service kubernetes-dashboard
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes-dashboard ClusterIP 10.103.58.176 <none> 80/TCP 13m
Con el proxy debería funcionar pero no lo he conseguido:
kubectl proxy
Yo he hecho un tunel y abierto en local:
ssh -L 8001:10.103.58.176:80 pi@192.168.69.1
Abrimos http://127.0.0.1:8001
Podemos acceder directamente al nodo, pero hay que habilitar la autenticación
Documentación: https://kubernetes.io/docs/tasks/access-application-cluster/web-ui-dashboard/#deploying-the-dashboard-ui
https://192.168.69.1:6443/api/v1/namespaces/kube-system/services/https:kubernetes-dashboard:/proxy/
Descargar la imagen con Desktop:
https://www.raspberrypi.com/software/operating-systems/
Raspberry Pi OS (64-bit) > Raspberry Pi OS with desktop
O instalamos las X
sudo apt-get install lightdm
En raspi-config seleccionamos la opción
1. System Options S5 Boot / Auto Login B4 Desktop Autologin Desktop GUI, automatically logged in as 'ruth' user
Para poder conectar con las X por vnc configuramos desde raspi-config:
3 Interface Options I3 VNC Enable/disable graphical remote access using RealVNC
Creo que es lo mismo que instalar:
realvnc-vnc-server
Para no poner contraseña:
/root/.vnc/config.d/vncserver-x11
Authentication=None Encryption=AlwaysOff
Si queremos contraseña ojo que tiene que ser de 6 a 8 carácteres con:
sudo vncpasswd -service -legacy
Para reiniciar el servicio
systemctl restart vncserver-x11-serviced.service
Nos aseguramos que tengamos instalado chromium-browser
~/.config/lxsession/LXDE/autostart
@chromium-browser --start-fullscreen --app=http://web.raspi
Instalamos las aplicaciones necesarias
apt-get install xdotool wmctrl
Exportamos DISPLAY para conectarnos a la pantalla:
export DISPLAY=:0
Para listar las aplicaciones abiertas:
wmctrl -l
0x01200004 0 raspberrypi VNC Server 0x01600002 0 raspberrypi Sign in [Jenkins] 0x0200000b 0 raspberrypi EmulationStation
Seleccionamos la que queremos llevar al frente
wmctrl -i -a 0x01200004
Ahora la podemos cerrar por ejemplo:
xdotool keydown Alt key F4
Vemos que se ha cerrado:
wmctrl -l
0x01600002 0 raspberrypi Sign in [Jenkins] 0x0200000b 0 raspberrypi EmulationStation
También podríamos cambiar entre aplicaciones simulando ALT+TAB
xdotool keydown Alt key Tab keyup Alt
Y con xdotool simular cualquier pulsación de teclas
git clone --depth=1 https://github.com/RetroPie/RetroPie-Setup.git
cd RetroPie-Setup chmod +x retropie_setup.sh sudo ./retropie_setup.sh
Seleccionar “Basic Install”
Para cambiar de una aplicación a otra remotamente:
sudo apt-get install xdotool
Cambiamos desde la conexión ssh al display del monitor:
export DISPLAY=:0
Lanzamos el comando ALT+TAB
xdotool keydown Alt key Tab keyup Alt
https://www.bogotobogo.com/DevOps/Docker/Docker_Prometheus_Grafana.php
Vienen 2 repositorios, he levantado este docker compose y monitoriza los dockers del nodo donde se ejecuta:
https://www.raspberrypi.com/documentation/computers/raspberry-pi.html
Con el comando pinout muestra un mapa de los pins
Instalamos python paquetes necesarios:
apt-get install python3-pip pip3 install RPi.GPIO