Kubernetes для бедных. Запускаем приложение
После того как мы настроили доступ по HTTP к приложениям в кластере Kubernetes, разместим в кластере собственно приложение.
Приложение должно поставляться в образе контейнера и уметь отвечать на запросы HTTP. Соберём контейнер Docker на базе Hugo. Для работы с собственными образами нужно быть зарегистрированным на одном из Docker Registry. Самое простое - использовать официальный Docker Hub. Образ, с которым мы будем работать, собирается так (потребуется Docker >= 17.05):
mkdir /tmp/hugo cd /tmp/hugo cat <<EOF > Dockerfile FROM alpine AS base RUN wget -O- https://github.com/gohugoio/hugo/releases/download/v0.49/hugo_0.49_Linux-64bit.tar.gz | tar xz RUN /hugo new site /site RUN wget -O- https://github.com/hauke96/hugo-theme-hamburg/archive/v0.4.4.tar.gz | tar xzC /site/themes RUN echo 'theme = "hugo-theme-hamburg-0.4.4"' >> /site/config.toml FROM alpine COPY --from=base /hugo / COPY --from=base /site /site WORKDIR /site EXPOSE 1313 ENTRYPOINT ["/hugo"] CMD ["server", "--bind", "0.0.0.0"] EOF docker build -t alxrem/hugoexample . docker push alxrem/hugoexample
Если захочется пересобрать образ самостоятельно, нужно будет заменить alxrem на название своей учётной записи.
После того, как образ собран, можно публиковать приложение в Kubernetes.
Нам потребуется создать три ресурса - Deployment, Service и Ingress. Выделим отдельный namespace:
kubectl create ns blogexample
При помощи Deployment разместим в кластере Kubernetes два экземпляра приложения: на случай отказа ноды и для более стабильного обновления:
cat <<EOF | kubectl -n blogexample create -f-
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: blogexample
name: blogexample
spec:
replicas: 2
selector:
matchLabels:
app: blogexample
template:
metadata:
labels:
app: blogexample
spec:
containers:
- name: www
image: alxrem/hugoexample
imagePullPolicy: Always
ports:
- containerPort: 1313
protocol: TCP
EOF
Создадим Service для определения доступа к контейнеру:
cat <<EOF | kubectl -n blogexample create -f-
apiVersion: v1
kind: Service
metadata:
labels:
app: blogexample
name: blogexample
spec:
ports:
- port: 80
protocol: TCP
targetPort: 1313
selector:
app: blogexample
type: ClusterIP
EOF
Теперь внутри кластера приложение будет доступно по адресу blogexample.blogexample.
Для доступа снаружи понадобится завести в DNS запись A, указывающую на внешние адреса нодов, которые мы помечали меткой remizov.org/ingress=true.
Для управления доступом создадим Ingress. Определим, что запросы к хосту blogexample.remizov.org будут отправляться на порт 80 сервиса blogexample. При этом выпишем для адреса blogexample.remizov.org сертификат от letsencrypt.org. В отличие от прошлого примера будем использовать боевой центр сертификации letsencrypt-v01:
cat <<EOF | kubectl -n blogexample create -f-
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
certmanager.k8s.io/cluster-issuer: letsencrypt-v01
kubernetes.io/ingress.class: nginx
name: blogexample
spec:
rules:
- host: blogexample.remizov.org
http:
paths:
- backend:
serviceName: blogexample
servicePort: 80
path: /
tls:
- hosts:
- blogexample.remizov.org
secretName: blogexample-tls
EOF
В итоге по адресу https://blogexample.remizov.org доступен блог с валидным сертификатом SSL