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