Hyppää sisältöön

Welcome to our weekly research support coffee hour on Zoom! Click here for more information.

Warning!

Puhti scratch disk is becoming very full (80+ % ) resulting in performance degradation. Everybody is advised to only keep actively processed data on scratch, all other data should be deleted, transferred to host institute or stored in Lumi-O. No new quota will be granted. Click here for a tool for examining your disk usage.

Edistynyt taso

Sinulla tulee olla Linuxin, Dockerin, Docker Composen ja Komposen tuntemusta. Python-osaaminen on plussaa.
Rahtin osalta suosimme OpenShiftin komentorivityökalun oc käyttöä

4catin käyttöönotto Rahdissa

Tämä ohje on pitkämuotoinen ja selittää kaikki eri vaiheet, joita tarvittiin 4cat_fi -sovelluksen käyttöönottoon Rahdissa. Tarkoituksena on kertoa, miten eri ongelmat löydettiin ja ratkaistiin. Jokaisella ongelmalla on oma lukunsa, ja toivottavasti ratkaisu on helppo soveltaa myös muihin sovelluksiin, joissa on samankaltaisia oireita. Jätämme pois osan virheellisistä ratkaisuista ja harhapoluista, joita seurasin yrittäessäni alun perin ottaa tätä sovellusta käyttöön, jotta tämä ohje ei kasvaisi eksponentiaalisesti. Pidä kuitenkin mielessä, että tällaiset prosessit ovat harvoin suoraviivaisia ja että ratkaisua etsiessä löytyy yleensä paljon myös ratkaisuja, jotka eivät toimi.

4Cat on datan keruu- ja analyysityökalupakki. Yllä linkitetystä GitHub-sivusta opimme, että työkalua käytetään sosiaalisen median alustojen analysointiin ja että yksi asennustavoista on docker compose. Tämä on hyvä uutinen, koska:

  1. Voimme testata sovelluksen käyttöönottoa docker composella ja nähdä, miltä se näyttää.
  2. Meidän ei tarvitse luoda Docker-konttia alusta asti.
  3. Voimme käyttää docker compose -käyttöönottoa pohjana ja sovittaa sen Kubernetes-käyttöönotoksi komposen avulla. Tämä työkalu on suunniteltu nimenomaan tällaisia muunnoksia varten. Heidän sivustonsa mukaan: "Our conversions are not always 1:1 from Docker Compose to Kubernetes, but we will help get you 99% of the way there!". Se säästääkin paljon työlästä muunnostyötä, mutta siihen työ ei vielä lopu.

Kaikissa esimerkeissä käytetään Linuxia 🐧

Olemme laatineet tämän ohjeen Linux-koneella. Periaatteessa pienellä sovittamisella kaikki nämä komennot toimivat myös Windowsissa ja Macissa, mutta jos olet epävarma, suosittelen, että asennat pienen virtuaalikoneen Poutaan ja käytät sitä tämän ohjeen seuraamiseen. Tämä on hyödyllistä myös Linux-käyttäjille, koska voit asentaa, poistaa tai vaihtaa ohjelmistoja vaarantamatta paikallista asennustasi.

Docker compose

  1. Ennen jatkamista tarvitsemme Dockerin ja docker compose -lisäosan asennettuna. Ohjeet docker composen asentamiseen löytyvät täältä:

    Debianissa ja Ubuntussa voit asentaa sen näin:

    sudo apt-get update
    sudo apt-get install docker.io docker-compose
    

    Vaihtoehtoja Dockerille 🐋

    Voit käyttää myös podman composea tai vastaavaa, mutta tässä ohjeessa käytämme Dockeria, koska se on yleisin työkalu.

  2. Kun docker compose on asennettu, otetaan 4cat käyttöön ja katsotaan, miltä se näyttää ja miten se toimii. Sinun täytyy kloonata repositorio ja suorittaa docker-compose kloonatun kansion sisällä:

    git clone https://github.com/uh-dcm/4cat_fi
    cd 4cat_fi
    sudo docker compose up
    

    Tämä käynnistää sovelluksen käyttöönoton koneella. Kuvien noutaminen ja sovelluksen määrittäminen voi kestää jonkin aikaa. Jos painat Ctrl+C, sovellus sulkeutuu. Jos haluat ajaa sen taustalla, lisää docker-compose-komentoon -d tai --detach.

    docker-compose output

    Hetken kuluttua sovellus on saatavilla portissa 80 (PUBLIC_PORT):

    4cat first run

Analyysi

docker-compose.yml -tiedosto on seuraava:

services:
  db:
    container_name: 4cat_db
    image: postgres:${POSTGRES_TAG}
    restart: unless-stopped
    environment:
      - POSTGRES_USER=${POSTGRES_USER}
      - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
      - POSTGRES_DB=${POSTGRES_DB}
      - POSTGRES_HOST_AUTH_METHOD=${POSTGRES_HOST_AUTH_METHOD}
    volumes:
      - 4cat_db:/var/lib/postgresql/data/
    healthcheck:
      test: [ "CMD-SHELL", "pg_isready -U $${POSTGRES_USER}" ]
      interval: 5s
      timeout: 5s
      retries: 5

  backend:
    image: digitalmethodsinitiative/4cat:${DOCKER_TAG}
    container_name: 4cat_backend
    restart: unless-stopped
    env_file:
      - .env
    depends_on:
      db:
        condition: service_healthy
    ports:
      - ${PUBLIC_API_PORT}:4444
    volumes:
      - 4cat_data:/usr/src/app/data/
      - 4cat_config:/usr/src/app/config/
      - 4cat_logs:/usr/src/app/logs/
    entrypoint: docker/docker-entrypoint.sh

  frontend:
    image: digitalmethodsinitiative/4cat:${DOCKER_TAG}
    container_name: 4cat_frontend
    restart: unless-stopped
    env_file:
      - .env
    depends_on:
      - db
      - backend
    ports:
      - ${PUBLIC_PORT}:500
      - ${TELEGRAM_PORT}:443
    volumes:
      - 4cat_data:/usr/src/app/data/
      - 4cat_config:/usr/src/app/config/
      - 4cat_logs:/usr/src/app/logs/
    command: ["docker/wait-for-backend.sh"]

volumes:
  4cat_db:
    name: ${DOCKER_DB_VOL}
  4cat_data:
    name: ${DOCKER_DATA_VOL}
  4cat_config:
    name: ${DOCKER_CONFIG_VOL}
  4cat_logs:
    name: ${DOCKER_LOGS_VOL}

Katsotaan myös .env -tiedostoa:

# 4CAT Version: Update with latest release tag or 'latest'
# https://hub.docker.com/repository/docker/digitalmethodsinitiative/4cat/tags?page=1&ordering=last_updated
DOCKER_TAG=stable
# You can select Postrgres Docker image tags here to suit your needs: https://hub.docker.com/_/postgres
POSTGRES_TAG=latest

# Database setup
POSTGRES_USER=fourcat
POSTGRES_PASSWORD=supers3cr3t
POSTGRES_DB=fourcat
POSTGRES_HOST_AUTH_METHOD=trust
# POSTGRES_HOST should correspond with the database container name set in docker-compose.yml
POSTGRES_HOST=db
POSTGRES_PORT=5432  # Docker postgres image uses port 5432

# Server information
# SERVER_NAME is only used on first run; afterwards it can be set in the frontend
SERVER_NAME=localhost
PUBLIC_PORT=80

# Backend API
# API_HOST is used by the frontend; in Docker it should be the backend container name
# (or "localhost" if front and backend are running together in one container
API_HOST=backend
PUBLIC_API_PORT=4444

# Telegram apparently needs its own port
TELEGRAM_PORT=443

# Docker Volume Names
DOCKER_DB_VOL=4cat_4cat_db
DOCKER_DATA_VOL=4cat_4cat_data
DOCKER_CONFIG_VOL=4cat_4cat_config
DOCKER_LOGS_VOL=4cat_4cat_logs

# Gunicorn settings
worker_tmp_dir=/dev/shm
workers=4
threads=4
worker_class=gthread
log_level=debug

Kuten näet, tämä docker-compose.yml-tiedosto on YAML -tiedosto, jossa on kaksi pääosiota: services ja volumes. Siinä on 3 services-määrittelyä ja 4 volumes-määrittelyä. Kubernetesissa tämä tarkoittaa 3:a Deployment-resurssia ja 4:ää PersistentVolumeClaim-resurssia (PVC). Palvelun tärkeimmät kentät ovat:

  • image on kuva, jonka Docker noutaa ja suorittaa jokaiselle palvelulle. Tässä tapauksessa meillä on kaksi eri kuvaa: postgres-kuva (tunnettu tietokanta) ja 4cat_fi-kuva. Frontend ja backend käyttävät samaa kuvaa, mutta niillä on eri komento/entry point. Koska docker compose toimii, tiedämme, että molemmat kuvat ovat olemassa ja ne voidaan noutaa ilman ongelmia.
  • environment ja env_file määrittelevät ympäristömuuttujat, joilla palvelut konfiguroidaan. Esimerkiksi POSTGRES_PASSWORD-muuttujaa käytetään tietokannan salasanan välittämiseen.
  • volumes kertoo Dockerille, mitkä taltiot liitetään palveluun ja mihin kansioon ne liitetään.
  • ports kertoo julkiset portit, sisäiset portit ja niiden välisen kartoituksen. Merkintätapa on <external_port>:<internal_port>.
  • entrypoint ja command ovat komennot, jotka suoritetaan, kun kuva käynnistetään. Postgresilla ei ole kumpaakaan, koska käytämme kuvan oletus-command/entrypoint-määrityksiä.

Taltiot-osio on yksinkertaisempi ja sisältää vain nimiluettelon. Docker composen "volume" on tavallinen Docker-taltio eikä sisällä kokoa. Tämä johtuu siitä, että se käyttää paikallista levyä, jolloin koko määräytyy paikallisen levyn kapasiteetin mukaan. Kubernetesin taltioilla on koko, ja meidän täytyy ottaa se huomioon muunnosta tehdessä.

.env-tiedosto sisältää oletusarvot sovelluksen oikeaan käyttöönottoon. Esimerkiksi PUBLIC_PORT on asetettu arvoon 80.

Kompose

Kompose antaa meille mahdollisuuden muuntaa docker-compose.yaml-tiedoston joukoksi Kubernetesin YAML-tiedostoja.

  1. Meillä täytyy olla kompose asennettuna. Voit seurata ohjeita täältä:

    Koska Docker on jo asennettu, voimme käyttää Docker-menetelmää, joka rakentaa kuvan lähdekoodista:

    sudo docker build -t kompose https://github.com/kubernetes/kompose.git\#main
    
  2. Suorita kompose (edelleen 4cat_fi-kansiossa):

    $ docker run --rm -it -v $PWD:/opt kompose sh -c "cd /opt && kompose convert"
    WARN The "DOCKER_CONFIG_VOL" variable is not set. Defaulting to a blank string.
    WARN The "DOCKER_LOGS_VOL" variable is not set. Defaulting to a blank string.
    WARN The "DOCKER_DB_VOL" variable is not set. Defaulting to a blank string.
    WARN The "DOCKER_DATA_VOL" variable is not set. Defaulting to a blank string.
    WARN The "PUBLIC_PORT" variable is not set. Defaulting to a blank string.
    WARN The "TELEGRAM_PORT" variable is not set. Defaulting to a blank string.
    WARN The "DOCKER_TAG" variable is not set. Defaulting to a blank string.
    WARN The "POSTGRES_TAG" variable is not set. Defaulting to a blank string.
    WARN The "POSTGRES_USER" variable is not set. Defaulting to a blank string.
    WARN The "POSTGRES_PASSWORD" variable is not set. Defaulting to a blank string.
    WARN The "POSTGRES_DB" variable is not set. Defaulting to a blank string.
    WARN The "POSTGRES_HOST_AUTH_METHOD" variable is not set. Defaulting to a blank string.
    WARN The "PUBLIC_API_PORT" variable is not set. Defaulting to a blank string.
    WARN The "DOCKER_TAG" variable is not set. Defaulting to a blank string.
    WARN Restart policy 'unless-stopped' in service frontend is not supported, convert it to 'always'
    WARN Restart policy 'unless-stopped' in service db is not supported, convert it to 'always'
    WARN Restart policy 'unless-stopped' in service backend is not supported, convert it to 'always'
    WARN File don't exist or failed to check if the directory is empty: stat :/usr/src/app/data: no such file or directory
    WARN File don't exist or failed to check if the directory is empty: stat :/usr/src/app/config: no such file or directory
    WARN File don't exist or failed to check if the directory is empty: stat :/usr/src/app/logs: no such file or directory
    WARN Service "db" won't be created because 'ports' is not specified
    WARN File don't exist or failed to check if the directory is empty: stat :/var/lib/postgresql/data: no such file or directory
    WARN File don't exist or failed to check if the directory is empty: stat :/usr/src/app/data: no such file or directory
    WARN File don't exist or failed to check if the directory is empty: stat :/usr/src/app/config: no such file or directory
    WARN File don't exist or failed to check if the directory is empty: stat :/usr/src/app/logs: no such file or directory
    INFO Kubernetes file "backend-service.yaml" created
    INFO Kubernetes file "frontend-service.yaml" created
    INFO Kubernetes file "backend-deployment.yaml" created
    INFO Kubernetes file "env-configmap.yaml" created
    INFO Kubernetes file "4cat-data-persistentvolumeclaim.yaml" created
    INFO Kubernetes file "4cat-config-persistentvolumeclaim.yaml" created
    INFO Kubernetes file "4cat-logs-persistentvolumeclaim.yaml" created
    INFO Kubernetes file "db-deployment.yaml" created
    INFO Kubernetes file "4cat-db-persistentvolumeclaim.yaml" created
    INFO Kubernetes file "frontend-deployment.yaml" created
    
  3. Sinulla pitäisi nyt olla muutama uusi tiedosto:

    • "backend-service.yaml"
    • "frontend-service.yaml"
    • "backend-deployment.yaml"
    • "env-configmap.yaml"
    • "4cat-data-persistentvolumeclaim.yaml"
    • "4cat-config-persistentvolumeclaim.yaml"
    • "4cat-logs-persistentvolumeclaim.yaml"
    • "db-deployment.yaml"
    • "4cat-db-persistentvolumeclaim.yaml"
    • "frontend-deployment.yaml"

Analyysi

Työkalu on luonut neljänlaisia tiedostoja: service, deployment, configmap ja persistentvolumeclaim. Aloitetaan yksinkertaisimmista:

  • persistentvolumeclaim-tiedostot ovat taltioiden määrittelyjä. Jokaisesta docker compose -tiedoston volume-määrittelystä syntyy yksi tiedosto. Katsotaan esimerkkiä ja olennaisten rivien merkitystä:

    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      labels:
        io.kompose.service: 4cat-logs
      name: 4cat-logs
    spec:
      accessModes:
        - ReadWriteOnce
      resources:
        requests:
          storage: 100Mi
    

    Näemme, että name on säilytetty compose-määrittelystä (kohdassa metadata > name). accessMode on asetettu arvoon ReadWriteOnce, mikä tarkoittaa, että taltio voidaan liittää vain kerran. Lopuksi koko on oletuksena 100Mi (kohdassa spec > resources > request > storage).

  • configmap-tiedosto(t) tallentavat konfiguraation. Meidän tapauksessamme .env-tiedostossa määritellyt (ei docker-compose-spesifiset) muuttujat on muunnettu tiedostoon env-configmap.yaml. name on asetettu arvoon env, ja muuttujat on määritelty kohdan data alle.

  • service-tiedostot määrittelevät "vakaat verkkoidentiteetit", jotka toimivat kuormantasaajina. Jokaiselle deployment-resurssille luodaan palvelu, ja se vie ulos kaikki portit, joita käyttöönotto tarjoaa. Esimerkiksi tiedostossa frontend-service.yaml:

    apiVersion: v1
    kind: Service
    metadata:
      annotations:
        kompose.cmd: kompose convert
        kompose.version: 1.34.0 (cbf2835db)
      labels:
        io.kompose.service: frontend
      name: frontend
    spec:
      ports:
        - name: "5000"
          port: 5000
          targetPort: 5000
        - name: "443"
          port: 443
          targetPort: 443
      selector:
        io.kompose.service: frontend
    

    Kaksi olennaista kohtaa ovat selector ja ports. Ensimmäinen yhdistää palvelun deployment-resurssiin ja toinen listaa portit, jotka tämä palvelu vie ulos. Katso lisätietoja palveluista.

  • deployment on monimutkaisin luotu määritys. Voimme yrittää kartoittaa docker-compose.yaml-tiedoston asetukset näihin tiedostoihin. Esimerkiksi käyttämällä lyhintä luotua tiedostoa:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      annotations:
        kompose.cmd: kompose convert
        kompose.version: 1.34.0 (cbf2835db)
      labels:
        io.kompose.service: db
      name: db
    spec:
      replicas: 1
      selector:
        matchLabels:
          io.kompose.service: db
      strategy:
        type: Recreate
      template:
        metadata:
          annotations:
            kompose.cmd: kompose convert
            kompose.version: 1.34.0 (cbf2835db)
          labels:
            io.kompose.service: db
        spec:
          containers:
            - env:
                - name: POSTGRES_DB
                - name: POSTGRES_HOST_AUTH_METHOD
                - name: POSTGRES_PASSWORD
                - name: POSTGRES_USER
              image: 'postgres:'
              livenessProbe:
                exec:
                  command:
                    - pg_isready -U ${POSTGRES_USER}
                failureThreshold: 5
                periodSeconds: 5
                timeoutSeconds: 5
              name: 4cat-db
              volumeMounts:
                - mountPath: /var/lib/postgresql/data
                  name: 4cat-db
          restartPolicy: Always
          volumes:
            - name: 4cat-db
              persistentVolumeClaim:
                claimName: 4cat-db
    
    • image on määritelty kohdassa spec > template > spec > containers > image, ja tässä tapauksessa se on postgres:. Tämä on virhe, koska tagi latest puuttuu. Korjaamme tämän myöhemmin.
    • environment on määritelty kohdassa spec > template > spec > containers > env, mutta myös arvot puuttuvat.
    • volumes on määritelty kohdissa spec > template > spec > volumes ja spec > template > spec > containers > volumeMounts.
    • ports on määritelty kohdassa spec > template > spec > containers > ports sekä jo mainituissa vastaavissa service-tiedostoissa.
    • Lopuksi command on määritelty kohdassa spec > template > spec > containers > command (näet esimerkin tiedostossa backend-deployment.yaml).

    Kuten näet, luodut YAML-tiedostot eivät ole täydellisiä, mutta ne toimivat hyvänä pohjana käyttöönoton jatkamiselle.

Käyttöönotto Rahdissa

Otamme nykyiset muokkaamattomat YAML-tiedostot ja otamme ne käyttöön yksi kerrallaan. Ensin sinun täytyy asentaa oc ja kirjautua Rahtiin. Sen jälkeen sinun täytyy luoda Rahti-projekti. Varmista lopuksi, että olet oikeassa projektissa: oc project <project_name>.

Taltiot, ConfigMapit ja palvelut

Nämä kolme tyyppiä ovat suoraviivaisia eikä niiden pitäisi aiheuttaa ongelmia.

  1. Voimme aloittaa luomalla volumes-resurssit yksi kerrallaan:

    $ oc create -f 4cat-config-persistentvolumeclaim.yaml
    persistentvolumeclaim/4cat-config created
    
    $ oc create -f 4cat-data-persistentvolumeclaim.yaml
    persistentvolumeclaim/4cat-data created
    
    $ oc create -f 4cat-db-persistentvolumeclaim.yaml
    persistentvolumeclaim/4cat-db created
    
    $ oc create -f 4cat-logs-persistentvolumeclaim.yaml
    persistentvolumeclaim/4cat-logs created
    

    Tämä luo 4 taltiota tilaan Pending. Ne pysyvät tilassa Pending, kunnes otamme deployments-resurssit käyttöön. Tämä on odotettua.

  2. Luomme myös configMap-resurssin:

    $ oc create -f env-configmap.yaml
    configmap/env created
    
    $ oc get cm
    NAME                       DATA   AGE
    env                        22     5s
    kube-root-ca.crt           1      5m45s
    openshift-service-ca.crt   1      5m45s
    

    Kaksi muuta merkintää (kube-root-cs.crt ja openshift-service-ca.crt) ovat valmiiksi luotuja Kubernetesin ja OpenShiftin perus-ConfigMap-resursseja.

  3. Emme odota virheitä services-resurssien luomisessa (db-palvelu puuttuu, koska docker compose -tiedostossa ei mainittu portteja, ja meidän täytyy luoda se itse myöhemmin):

    $ oc create -f frontend-service.yaml
    service/frontend created
    
    $ oc create -f backend-service.yaml
    service/backend created
    
    $ oc get service
    NAME       TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)            AGE
    backend    ClusterIP   172.30.109.120   <none>        4444/TCP           21h
    frontend   ClusterIP   172.30.139.56    <none>        5000/TCP,443/TCP   21h
    

    Tulos on backendin osalta odotettu, koska kartoitus oli 4444:4444. Frontendin osalta ei, koska alkuperäinen oli 80:5000. Tämä ei ole suuri ongelma, koska jotta palveluun pääsee Rahdin ulkopuolelta, käytämme Route-resurssia, ja Route mahdollistaa minkä tahansa portin muuntamisen ja julkaisemisen vakioporteissa 80/443. Jätämme sen siis ennalleen.

Tietokannan Deploymentit

Lopuksi luomme deploymentit. Meillä on 3 deploymentia, ja aloitamme tietokannan deploymentista.

  1. Luodaan ensin nykyinen versio:

    $ oc create -f db-deployment.yaml
    deployment.apps/db created
    
    $ oc get pods
    NAME                  READY   STATUS             RESTARTS   AGE
    db-66db46fb89-vzqrz   0/1     InvalidImageName   0          26s
    
  2. Tämä on odotettua, koska tagi latest puuttui kuvan nimestä. Korjataan se ja yritetään uudelleen. Muokkaa siis tiedostoa db-deployment.yaml ja lisää latest kuvan arvoon niin, että se näyttää tältä: postgres:latest,

                 - name: POSTGRES_USER
    -          image: 'postgres:'
    +          image: 'postgres:latest'
               livenessProbe:
                 exec:
    

    ja luo deployment uudelleen / korvaa se:

    $ oc replace -f db-deployment.yaml
    deployment.apps/db replaced
    
    $ oc get pods
    NAME                  READY   STATUS              RESTARTS   AGE
    db-76fcbdc9d8-dgmqr   0/1     CrashLoopBackOff    1 (1s ago)   24s
    

    YAML-tiedostot

    Teemme muutokset YAML-tiedostoihin, jotta voimme myöhemmin luoda koko käyttöönoton uudelleen. Voit myös lisätä tiedostot Git-repositorioon ja tehdä commitin jokaisesta muutoksesta, jolloin muutosten historia ja perustelut säilyvät selkeästi commit-historiassa.

  3. Deployment ei toimi, mutta eri syystä. Katsotaan miksi:

    $ oc logs db-76fcbdc9d8-dgmqr
    chmod: changing permissions of '/var/lib/postgresql/data': Operation not permitted
    chmod: changing permissions of '/var/run/postgresql': Operation not permitted
    Error: Database is uninitialized and superuser password is not specified.
           You must specify POSTGRES_PASSWORD to a non-empty value for the
           superuser. For example, "-e POSTGRES_PASSWORD=password" on "docker run".
    
           You may also use "POSTGRES_HOST_AUTH_METHOD=trust" to allow all
           connections without a password. This is *not* recommended.
    
           See PostgreSQL documentation about "trust":
           https://www.postgresql.org/docs/current/auth-trust.html
    

    Tämä näyttää kahdenlaisia virheitä: kansioiden käyttöoikeusvirheitä ja puuttuvia muuttujia. Yritetään toistaa virhe paikallisesti omalla koneellamme. Komento on:

    docker run -it --rm -u 1000 postgres:latest
    chmod: changing permissions of '/var/lib/postgresql/data': Operation not permitted
    chmod: changing permissions of '/var/run/postgresql': Operation not permitted
    Error: Database is uninitialized and superuser password is not specified.
           You must specify POSTGRES_PASSWORD to a non-empty value for the
           superuser. For example, "-e POSTGRES_PASSWORD=password" on "docker run".
    
           You may also use "POSTGRES_HOST_AUTH_METHOD=trust" to allow all
           connections without a password. This is *not* recommended.
    
           See PostgreSQL documentation about "trust":
           https://www.postgresql.org/docs/current/auth-trust.html
    

    Yllä olevassa esimerkissä lisäsimme -u 1000, jotta UID vaihdetaan ei-root-käyttäjäksi ja voimme toistaa saman virheen, jonka Rahti näyttää. Mikä tahansa satunnainen UID käy; näin Rahti suorittaa kuvia (satunnaisilla UID:illa). Toistetaan tämä niin, että POSTGRES_PASSWORD-muuttuja on määritelty ehdotuksen mukaisesti:

    $ podman run -it --rm -u 1000 -e  POSTGRES_PASSWORD=password postgres:latest
    WARN[0000] Error validating CNI config file /home/galvaro/.config/cni/net.d/4cat_default.conflist: [plugin firewall does not support config version "1.0.0"]
    chmod: changing permissions of '/var/lib/postgresql/data': Operation not permitted
    chmod: changing permissions of '/var/run/postgresql': Operation not permitted
    The files belonging to this database system will be owned by user "1000".
    This user must also own the server process.
    
    The database cluster will be initialized with locale "en_US.utf8".
    The default database encoding has accordingly been set to "UTF8".
    The default text search configuration will be set to "english".
    
    Data page checksums are disabled.
    
    fixing permissions on existing directory /var/lib/postgresql/data ... initdb: error: could not change permissions of directory "/var/lib/postgresql/data": Operation not permitted
    

    Tässä tapauksessa näemme, että tämä konttikuva ei koskaan toimi Rahdissa, koska sen täytyy pystyä muuttamaan kansioiden käyttöoikeuksia. Onneksi Rahti/OpenShift tarjoaa PostgreSQL-mallin, joka on saatavilla ohjelmistoluettelossa.

    Developer Catalog

    Mallin kuvauksessa näemme linkin GitHub-sivulle https://github.com/sclorg/postgresql-container/. Sivulla näkyy lista kaikista saatavilla olevista kuvista. Valitsemme quay.io/sclorg/postgresql-15-c9s -kuvan, koska se on uusin saatavilla oleva versio ja käyttää CentOS 9:ää pohjana.

  4. Kun kuva on vaihdettu (postgres:latestquay.io/sclorg/postgresql-15-c9s:latest), lokit näyttävät tältä:

    $ oc logs db-747df6885c-sh289
    For general container run, you must either specify the following environment
    variables:
      POSTGRESQL_USER  POSTGRESQL_PASSWORD  POSTGRESQL_DATABASE
    Or the following environment variable:
      POSTGRESQL_ADMIN_PASSWORD
    Or both.
    
    To migrate data from different PostgreSQL container:
      POSTGRESQL_MIGRATION_REMOTE_HOST (hostname or IP address)
      POSTGRESQL_MIGRATION_ADMIN_PASSWORD (password of remote 'postgres' user)
    And optionally:
      POSTGRESQL_MIGRATION_IGNORE_ERRORS=yes (default is 'no')
    
    Optional settings:
      POSTGRESQL_MAX_CONNECTIONS (default: 100)
      POSTGRESQL_MAX_PREPARED_TRANSACTIONS (default: 0)
      POSTGRESQL_SHARED_BUFFERS (default: 32MB)
    
    For more information see /usr/share/container-scripts/postgresql/README.md
    within the container or visit https://github.com/sclorg/postgresql-container.
    

    Muuttujien nimet ovat erilaiset, mutta ne on helppo muuntaa. Otamme myös arvot env-configMap-resurssista:

           containers:
             - env:
    -            - name: POSTGRES_DB
    -            - name: POSTGRES_HOST_AUTH_METHOD
    -            - name: POSTGRES_PASSWORD
    -            - name: POSTGRES_USER
    -          image: 'postgres:'
    +          - name: POSTGRESQL_DATABASE
    +            valueFrom:
    +              configMapKeyRef:
    +                key: POSTGRES_DATABASE
    +                name: env
    +          - name: POSTGRESQL_PASSWORD
    +            valueFrom:
    +              configMapKeyRef:
    +                key: POSTGRES_PASSWORD
    +                name: env
    +          - name: POSTGRESQL_USER
    +            valueFrom:
    +              configMapKeyRef:
    +                key: POSTGRES_USER
    +                name: env
    +          image: 'quay.io/sclorg/postgresql-15-c9s'
               livenessProbe:
                 exec:
    

    Tämä viimeinen muutos ratkaisi ongelman, ja Pod on nyt käynnissä odotetusti:

    $ oc get pods
    NAME                  READY   STATUS    RESTARTS   AGE
    db-58947cf497-p4vnq   1/1     Running   0          66s
    

Backend-deployment

Tämä deployment tarvitsee myös muutamia muutoksia. Käydään ne läpi toivottavasti hieman ketterämmin:

  1. Korjaa kuvan nimi. Virhe:

    $ oc get pods
    NAME                       READY   STATUS             RESTARTS   AGE
    backend-7f47d4c5d4-zrxjp   0/1     InvalidImageName   0          41s
    

    Ratkaisu:

                       key: workers
                       name: env
    -          image: 'digitalmethodsinitiative/4cat:'
    +          image: 'digitalmethodsinitiative/4cat:stable'
               name: 4cat-backend
               ports:
    
  2. Lisää db-palvelu ratkaistaksesi tämän ongelman:

    db: forward host lookup failed: Unknown host
    

    Tämä edellyttää db-palvelun luomista:

    $ oc expose deploy/db --port 5432
    service/db exposed
    
  3. Seuraava virhe liittyy salasana-autentikointiin:

    Password for user fourcat:
    psql: error: connection to server at "db" (172.30.154.239), port 5432 failed: fe_sendauth: no password supplied
    

    Tämä johtuu siitä, että vaikka määrittelemme POSTGRESQL_PASSWORD, sovellus odottaa muuttujaa PGPASSWPRD. Tämä tarkoittaa, että korjaus on:

                       key: POSTGRES_HOST_AUTH_METHOD
                       name: env
    -            - name: POSTGRES_PASSWORD
    +            - name: PGPASSWORD
                   valueFrom:
                     configMapKeyRef:
    
  4. Backend-Podin tuloste on nyt paljon pidempi, mutta päättyy tähän virheeseen:

    During handling of the above exception, another exception occurred:
    
    Traceback (most recent call last):
      File "helper-scripts/migrate.py", line 336, in <module>
        finish(args, logger, no_pip=pip_ran)
      File "helper-scripts/migrate.py", line 122, in finish
        check_for_nltk()
      File "helper-scripts/migrate.py", line 74, in check_for_nltk
        nltk.download('punkt_tab', quiet=True)
      File "/usr/local/lib/python3.8/site-packages/nltk/downloader.py", line 774, in download
        for msg in self.incr_download(info_or_id, download_dir, force):
      File "/usr/local/lib/python3.8/site-packages/nltk/downloader.py", line 642, in incr_download
        yield from self._download_package(info, download_dir, force)
      File "/usr/local/lib/python3.8/site-packages/nltk/downloader.py", line 698, in _download_package
        os.makedirs(download_dir, exist_ok=True)
      File "/usr/local/lib/python3.8/os.py", line 223, in makedirs
        mkdir(name, mode)
    PermissionError: [Errno 13] Permission denied: '/nltk_data'
    

    Meidän täytyy tehdä kansiosta /nltk_data kirjoitettava sovellusta ajavalle käyttäjälle. Jos palaamme tarkistamaan docker compose -määritystä, tätä kansiota ei mainittu siellä. Koska kontit ovat tilattomia, tämä tarkoittaa, että kansioon kirjoitettu data ei säily konttia uudelleenkäynnistettäessä. Helpoin tapa toteuttaa tämä on liittää ephemeral storage -kansio (tai emptyDir). Tämä on nopea väliaikainen tallennustila, joka poistetaan, kun Pod lopetetaan, eli sama toimintatapa kuin docker composessa. Muutos on seuraava:

                   protocol: TCP
               volumeMounts:
    +            - mountPath: /nltk_data
    +              name: nltk-data
                 - mountPath: /usr/src/app/data
                   name: 4cat-data
    @@ -151,4 +153,6 @@
           restartPolicy: Always
           volumes:
    +        - name: nltk-data
    +          emptyDir: {}
             - name: 4cat-data
               persistentVolumeClaim:
    
  5. Seuraava virhe liittyy jälleen ympäristömuuttujiin:

    Creating config/config.ini file
    Traceback (most recent call last):
      File "/usr/local/lib/python3.8/runpy.py", line 194, in _run_module_as_main
        return _run_code(code, main_globals, None,
      File "/usr/local/lib/python3.8/runpy.py", line 87, in _run_code
        exec(code, run_globals)
      File "/usr/src/app/docker/docker_setup.py", line 88, in <module>
        update_config_from_environment(CONFIG_FILE, config_parser)
      File "/usr/src/app/docker/docker_setup.py", line 35, in update_config_from_environment
        config_parser['DATABASE']['db_password'] = os.environ['POSTGRES_PASSWORD']
      File "/usr/local/lib/python3.8/os.py", line 675, in __getitem__
        raise KeyError(key) from None
    KeyError: 'POSTGRES_PASSWORD'
    

    Tämä ympäristömuuttuja on kovakoodattu sovelluksen lähdekoodiin. Voisimme paikata koodin, mutta silloin kuva pitäisi rakentaa uudelleen ja paikkausta pitäisi ylläpitää jokaiselle uudelle kuvan versiolle. Kustannustehokkain ratkaisu on määritellä muuttuja kahdesti. Jos muistat, tämän luvun vaiheessa 3 vaihdoimme muuttujan nimen tyydyttääksemme toista osaa koodista.

                       key: POSTGRES_PASSWORD
                       name: env
    +            - name: POSTGRES_PASSWORD
    +              valueFrom:
    +                configMapKeyRef:
    +                  key: POSTGRES_PASSWORD
    +                  name: env
                 - name: POSTGRES_PORT
                   valueFrom:
    
  6. Edistymme, mutta emme ole vielä valmiita. Uusi virhe on:

    $ oc logs backend-7f9c9dbfbb-78sh8 -f
    Waiting for postgres...
    PostgreSQL started
    Database already created
    
               4CAT migration agent
    ------------------------------------------
    Interactive:             no
    Pull latest release:     no
    Pull branch:             no
    Restart after migration: no
    Repository URL:          https://github.com/digitalmethodsinitiative/4cat.git
    .current-version path:   config/.current-version
    Current Datetime:        2024-12-12 07:00:22
    
    WARNING: Migration can take quite a while. 4CAT will not be available during migration.
    If 4CAT is still running, it will be shut down now (forcibly if necessary).
    
    - No PID file found, assuming 4CAT is not running
    - Version last migrated to: 1.46
    - Code version: 1.46
      ...already up to date.
    
    Migration finished. You can now safely restart 4CAT.
    
    Creating config/config.ini file
    Created config/config.ini file
    
    Starting app
    4CAT is accessible at:
    http://localhost
    
    Starting 4CAT Backend Daemon...
    ...error while starting 4CAT Backend Daemon (pidfile not found).
    tail: cannot open 'logs/backend_4cat.log' for reading: No such file or directory
    tail: no files remaining
    

    Tämän ongelman ratkaisemiseksi meillä on taas kaksi vaihtoehtoa: voimme arvata tai käyttää oc debug -työkalua. oc debug mahdollistaa epäonnistuneen podin käynnistämisen interaktiiviseen istuntoon ilman, että Podin alkuperäistä komentoa suoritetaan.

    $ oc debug backend-7f9c9dbfbb-78sh8
    Starting pod/backend-7f9c9dbfbb-78sh8-debug-vcb6f, command was: docker/docker-entrypoint.sh
    Pod IP: 10.129.12.120
    If you don't see a command prompt, try pressing enter.
    
    $ ls logs
    4cat.stderr  lost+found  migrate-backend.log
    $ df -h
    Filesystem      Size  Used Avail Use% Mounted on
    overlay         1.2T  435G  766G  37% /
    tmpfs            64M     0   64M   0% /dev
    shm              64M     0   64M   0% /dev/shm
    tmpfs            22G   91M   22G   1% /etc/passwd
    /dev/sda4        90G   17G   73G  19% /nltk_data
    /dev/sdr        974M   24K  958M   1% /usr/src/app/data
    /dev/sds        974M   36K  958M   1% /usr/src/app/config
    /dev/sdq        974M  168K  958M   1% /usr/src/app/logs
    tmpfs           1.0G   24K  1.0G   1% /run/secrets/kubernetes.io/serviceaccount
    devtmpfs        4.0M     0  4.0M   0% /proc/keys
    $
    

    Näemme siis, että logs-kansio on pysyvä taltio eikä lokitiedostoa todellakaan ole siellä. Ratkaisu voisi olla yksinkertaisesti tiedoston luominen, kun olemme vielä debug-istunnossa:

    $ touch logs/backend_4cat.log
    

    On outoa, ettei sovellus luo tiedostoa itse ja ettei tämä ollut ongelma compose-lähestymistavassa. Se on epäilyttävää, mutta jatkamme ja katsomme, aiheuttaako tämä myöhemmin ongelmia. Jotta näemme, ratkaisiko tämä ongelman, meidän täytyy poistaa Pod, jotta uusi luodaan:

    $ oc get pods
    NAME                       READY   STATUS    RESTARTS        AGE
    backend-7f9c9dbfbb-78sh8   1/1     Running   7 (7m49s ago)   21m
    db-545945c9b8-tkbwc        1/1     Running   0               17h
    
    $ oc delete pod backend-7f9c9dbfbb-78sh8
    pod "backend-7f9c9dbfbb-78sh8" deleted
    
  7. Katsotaan sitten, epäonnistuuko Pod edelleen:

    $ oc get pods
    NAME                       READY   STATUS    RESTARTS   AGE
    backend-7f9c9dbfbb-sznxl   1/1     Running   0          3m22s
    db-545945c9b8-tkbwc        1/1     Running   0          17h
    

    Se on ollut käynnissä muutaman minuutin kaatumatta, mikä on hyvä. Loki näyttää kuitenkin nyt uuden virheen, mikä ei ole yhtä hyvä:

    $ oc logs backend-7f9c9dbfbb-sznxl
    [...]
    Starting 4CAT Backend Daemon...
    ...error while starting 4CAT Backend Daemon (pidfile not found).
    

    Oletamme, että sovellus yrittää kirjoittaa PID-tiedoston (tiedosto, jossa on prosessin numero; yleinen käytäntö Unixissa) kansioon, johon voi kirjoittaa vain root. Tämä on tyypillinen virhe tällaisissa muunnoksissa. Loki ei kerro, missä PID-tiedoston pitäisi olla, joten meidän täytyy selvittää se itse. Koska Pod on käynnissä, voimme käyttää oc rsh -työkalua, jolla avataan etäkuori. Tämä toimii vain käynnissä oleviin Podeihin:

    $ oc rsh deploy/backend
        $ grep 'pidfile not' -C 4 -nR *
        4cat-daemon.py-144-            else:
        4cat-daemon.py-145-                time.sleep(0.1)
        4cat-daemon.py-146-
        4cat-daemon.py-147-        if not pidfile.is_file():
        4cat-daemon.py:148:            print("...error while starting 4CAT Backend Daemon (pidfile not found).")
        4cat-daemon.py-149-            return False
        4cat-daemon.py-150-
        4cat-daemon.py-151-        else:
        4cat-daemon.py-152-            with pidfile.open() as infile:
    
        $ grep pidfile 4cat-daemon.py
        pidfile = config.get('PATH_ROOT').joinpath(config.get('PATH_LOCKFILE'), "4cat.pid")  # pid file location
        if pidfile.is_file():
            with pidfile.open() as infile:
    

    Grep-työkalu

    Käytimme grep-työkalua löytääksemme virheilmoituksen koodista ja sitten uudelleen nähdäksemme, missä ja miten pidfile-muuttuja oli määritelty. Olisimme voineet käyttää paikallista tekstieditoria tai suoraan GitHub-hakua. Mielestäni grep on kuitenkin erinomainen työkalu, ja kaikkien kannattaa opetella sen käyttöä.

    Nyt tiedämme, että PID-tiedosto tallennetaan kansioon, joka on määritelty muuttujalla PATH_LOCKFILE. Tarkistetaan, löytyykö se config.ini-tiedostosta:

    $ oc rsh deploy/backend
        $ grep path -i config/config.ini
        [PATHS]
        path_images = data
        path_data = data
        path_lockfile = backend
        path_sessions = config/sessions
        path_logs = logs/
        $ ls -alh backend
        total 24K
        drwxr-xr-x. 1 root root  108 Oct 14 10:52 .
        drwxr-xr-x. 1 root root   30 Dec 12 07:22 ..
        -rw-r--r--. 1 root root  919 Oct 14 10:52 README.md
        -rw-r--r--. 1 root root   92 Oct 14 10:52 __init__.py
        -rw-r--r--. 1 root root 3.4K Oct 14 10:52 bootstrap.py
        -rw-r--r--. 1 root root 4.7K Oct 14 10:52 database.sql
        drwxr-xr-x. 2 root root  157 Oct 14 10:52 lib
        drwxr-xr-x. 2 root root 4.0K Oct 14 10:52 workers
    

    Tämä oli luultavasti yksi vaikeimmista korjattavista ongelmista ja vaati eniten arvailua. Ratkaisuna muutamme ensin asetuksen path_lockfile toiseen arvoon. Esimerkiksi pid, joka on mielestäni kuvaava nimi kansiolle. Koska config.ini on taltiolla, voimme muuttaa arvon suoraan Podissa (sed -i 's#path_lockfile = backend#path_lockfile = pid#' config/config.ini) tai kopioida tiedoston paikalliselle koneelle (katso oc cp), muokata sitä tekstieditorilla ja kopioida takaisin. Toiseksi lisäämme pid-kansion emptyDir-taltiona:

    @@ -150,4 +150,6 @@
                 - mountPath: /nltk_data
                   name: nltk-data
    +            - mountPath: /usr/src/app/pid
    +              name: pid
                 - mountPath: /usr/src/app/data
                   name: 4cat-data
    @@ -160,4 +162,6 @@
             - name: nltk-data
               emptyDir: {}
    +        - name: pid
    +          emptyDir: {}
             - name: 4cat-data
               persistentVolumeClaim:
    
  8. Seuraava virhe on tämä:

    $ oc logs backend-65cb8dc8dd-8thwg
    
    12-12-2024 12:40:44 | INFO at api.py:54: Could not open port 4444 yet ([Errno 99] Cannot assign requested address), retrying in 10 seconds
    12-12-2024 12:40:54 | INFO at api.py:54: Could not open port 4444 yet ([Errno 99] Cannot assign requested address), retrying in 10 seconds
    12-12-2024 12:41:04 | INFO at api.py:54: Could not open port 4444 yet ([Errno 99] Cannot assign requested address), retrying in 10 seconds
    12-12-2024 12:41:14 | INFO at api.py:54: Could not open port 4444 yet ([Errno 99] Cannot assign requested address), retrying in 10 seconds
    12-12-2024 12:41:24 | INFO at api.py:54: Could not open port 4444 yet ([Errno 99] Cannot assign requested address), retrying in 10 seconds
    12-12-2024 12:41:34 | INFO at api.py:54: Could not open port 4444 yet ([Errno 99] Cannot assign requested address), retrying in 10 seconds
    

    Tässä tapauksessa saamme tiedoston ja rivin, jossa virhe tapahtuu: app.py rivi 54. Olennaiset osat tiedostosta app.py ovat nämä:

      host = config.get('API_HOST')
      port = config.get('API_PORT')
    
    while has_time:
            has_time = start_trying > time.time() - 300  # stop trying after 5 minutes
            try:
                server.bind((self.host, self.port))
                break
            except OSError as e:
                if has_time and not self.interrupted:
                    self.manager.log.info("Could not open port %i yet (%s), retrying in 10 seconds" % (self.port, e))
                    time.sleep(10.0)  # wait a few seconds before retrying
                    continue
                self.manager.log.error("Port %s is already in use! Local API not available. Check if a residual 4CAT process may still be listening at the port." % self.port)
                return
            except ConnectionRefusedError:
                self.manager.log.error("OS refused listening at port %i! Local API not available." % self.port)
                return
    

    Rivillä 50 oleva funktio yrittää sitoa portin annettuun isäntänimeen. Compose-lähestymistavassa isäntänimi on backend, mutta Kubernetesissa tämä ei pidä paikkaansa, koska Podeilla on (osittain) satunnainen nimi. Voisimme muuttaa asetuksen arvosta backend arvoon 0.0.0.0, jolloin backend toimisi. Valitettavasti frontend käyttää samaa asetustiedostoa, koska ne jakavat saman taltion.

    Konfiguraatio taltiolla

    Konfiguraatioiden tallentaminen taltiolle ja niiden jakaminen deploymentien välillä on huono käytäntö. Konfiguraatiotiedostoja ei pitäisi muuttaa lennossa. Lisäksi eri deploymentit saattavat tarvita eri konfiguraation.

    Tällaisissa sovelluskäyttöönotossa on valitettavasti usein parasta muuttaa mahdollisimman vähän, jotta päivityksiä voidaan edelleen saada upstreamista. Tässä tapauksessa yritämme kopioida konfiguraatiotaltion: yksi frontendille ja toinen backendille (ja "teeskentelemme, ettemme koskaan nähneet tätä"):

    $ cp 4cat-config-persistentvolumeclaim.yaml 4cat-config-front-persistentvolumeclaim.yaml
    
    $ diff 4cat-config-persistentvolumeclaim.yaml 4cat-config-front-persistentvolumeclaim.yaml -U 2
    --- 4cat-config-persistentvolumeclaim.yaml  2024-12-10 15:48:29.123813479 +0200
    +++ 4cat-config-front-persistentvolumeclaim.yaml    2024-12-12 15:55:41.207227320 +0200
    @@ -4,5 +4,5 @@
       labels:
         io.kompose.service: 4cat-config
    -  name: 4cat-config
    +  name: 4cat-config-front
     spec:
       accessModes:
    
    $ oc create -f 4cat-config-front-persistentvolumeclaim.yaml
    persistentvolumeclaim/4cat-config-front created
    

    Meidän täytyy myös muokata env-configMap-resurssia, koska backend ylikirjoittaa config.ini-tiedoston ConfigMapin arvoilla käynnistyessään (toinen asia, josta en erityisesti pidä):

     apiVersion: v1
     data:
    -  API_HOST: backend
    +  API_HOST: 0.0.0.0
       DOCKER_CONFIG_VOL: 4cat_4cat_config
       DOCKER_DATA_VOL: 4cat_4cat_data
    
    $ oc replace -f env-configmap.yaml
    configmap/env replaced
    

Tämän pitäisi olla kaikki backendiin tarvittavat muutokset:

12-12-2024 14:03:30 | INFO at api.py:65: Local API listening for requests at 0.0.0.0:4444

Frontend-deployment

Tämä on viimeinen korjattava osa.

  1. Ennen frontendin käyttöönottoa meidän täytyy muuttaa deployment-tiedostoa käyttämään uutta taltiota:

    @@ -158,5 +168,5 @@
             - name: 4cat-config
               persistentVolumeClaim:
    -            claimName: 4cat-config
    +            claimName: 4cat-config-front
             - name: 4cat-logs
               persistentVolumeClaim:
    
  2. Otetaan nyt frontend käyttöön ja katsotaan tulos:

    $ oc create -f frontend-deployment.yaml
    deployment.apps/frontend created
    
    $ oc get pods
    NAME                        READY   STATUS             RESTARTS   AGE
    backend-7f9c9dbfbb-sznxl    1/1     Running            0          125m
    db-545945c9b8-tkbwc         1/1     Running            0          19h
    frontend-6b99c94fff-fv5wd   0/1     InvalidImageName   0          2s
    

    ...saamme tutun virheen, johon on tuttu ratkaisu:

                       key: workers
                       name: env
    -          image: 'digitalmethodsinitiative/4cat:'
    +          image: 'digitalmethodsinitiative/4cat:stable'
               name: 4cat-frontend
               ports:
    
  3. Nyt Pod käynnistyy vihdoin, mutta se ei saa yhteyttä backendiin:

    $ oc replace -f frontend-deployment.yaml
    deployment.apps/frontend replaced
    
    $ oc get pods
    NAME                       READY   STATUS    RESTARTS   AGE
    backend-7f9c9dbfbb-sznxl   1/1     Running   0          127m
    db-545945c9b8-tkbwc        1/1     Running   0          19h
    frontend-9ffbcf6b-wfg98    1/1     Running   0          4s
    
    $ oc logs frontend-9ffbcf6b-wfg98 -f
    Backend has not started - sleeping
    Backend has not started - sleeping
    Backend has not started - sleeping
    Backend has not started - sleeping
    Backend has not started - sleeping
    Backend has not started - sleeping
    Backend has not started - sleeping
    Backend has not started - sleeping
    Backend has not started - sleeping
    Backend has not started - sleeping
    Backend has not started - sleeping
    Backend has not started - sleeping
    

    Jos katsomme frontendin konfiguraatiokansiota (/usr/src/app/config/), se on tyhjä. Tämä on helppo ratkaista: kopioimme asetustiedoston backend-kansiosta käyttäen oc cp:

    $ oc cp backend-65cb8dc8dd-nxq6p:config/config.ini config.ini
    

    Muokkaa tiedostoa vaihtamalla api_host palvelun nimeksi:

         [API]
     api_port = 4444
    -api_host = 0.0.0.0
    +api_host = backend
    
     [PATHS]
    

    Kopioi muokattu tiedosto uuteen kansioon:

    $ oc cp config.ini frontend-79864b8548-pvh8z:config/
    
  4. Ratkaisun jälkeen saamme virheen, jonka näimme myös backendissä:

    During handling of the above exception, another exception occurred:
    
    Traceback (most recent call last):
      File "/usr/local/lib/python3.8/runpy.py", line 185, in _run_module_as_main
        mod_name, mod_spec, code = _get_module_details(mod_name, _Error)
      File "/usr/local/lib/python3.8/runpy.py", line 111, in _get_module_details
        __import__(pkg_name)
      File "/usr/src/app/helper-scripts/migrate.py", line 336, in <module>
        finish(args, logger, no_pip=pip_ran)
      File "/usr/src/app/helper-scripts/migrate.py", line 122, in finish
        check_for_nltk()
      File "/usr/src/app/helper-scripts/migrate.py", line 74, in check_for_nltk
        nltk.download('punkt_tab', quiet=True)
      File "/usr/local/lib/python3.8/site-packages/nltk/downloader.py", line 774, in download
        for msg in self.incr_download(info_or_id, download_dir, force):
      File "/usr/local/lib/python3.8/site-packages/nltk/downloader.py", line 642, in incr_download
        yield from self._download_package(info, download_dir, force)
      File "/usr/local/lib/python3.8/site-packages/nltk/downloader.py", line 698, in _download_package
        os.makedirs(download_dir, exist_ok=True)
      File "/usr/local/lib/python3.8/os.py", line 223, in makedirs
        mkdir(name, mode)
    PermissionError: [Errno 13] Permission denied: '/nltk_data'
    

    Tämä ratkaistaan samalla tavalla:

    @@ -145,4 +155,6 @@
                   protocol: TCP
               volumeMounts:
    +            - mountPath: /nltk_data
    +              name: nltk-data
                 - mountPath: /usr/src/app/data
                   name: 4cat-data
    @@ -153,4 +165,6 @@
           restartPolicy: Always
           volumes:
    +        - name: nltk-data
    +          emptyDir: {}
             - name: 4cat-data
               persistentVolumeClaim:
    
  5. Lopulta frontend käynnistyy. Näemme, että se kuuntelee porttia 5000, kuten odotettua:

    [2024-12-13 05:53:41 +0000] [35] [INFO] Starting gunicorn 23.0.0
    [2024-12-13 05:53:41 +0000] [35] [DEBUG] Arbiter booted
    [2024-12-13 05:53:41 +0000] [35] [INFO] Listening at: http://0.0.0.0:5000 (35)
    [2024-12-13 05:53:41 +0000] [35] [INFO] Using worker: gthread
    [2024-12-13 05:53:41 +0000] [37] [INFO] Booting worker with pid: 37
    [2024-12-13 05:53:41 +0000] [39] [INFO] Booting worker with pid: 39
    [2024-12-13 05:53:41 +0000] [41] [INFO] Booting worker with pid: 41
    [2024-12-13 05:53:41 +0000] [43] [INFO] Booting worker with pid: 43
    [2024-12-13 05:53:41 +0000] [35] [DEBUG] 4 workers
    
  6. Pian tämän jälkeen saamme kuitenkin käyttöoikeusvirheen:

    PermissionError: [Errno 13] Permission denied: '/usr/src/app/webtool/static/css/colours.css'
    

    Kansiolla /usr/src/app/webtool/static/css/ on käyttöoikeudet drwxr-xr-x. Tämä tarkoittaa, että vain omistaja (root) voi kirjoittaa siihen. Emme voi käyttää tässä emptyDir-ratkaisua, koska kansio ei ole alkuperäisessä kuvassa tyhjä:

    root@5878384231b9:/usr/src/app# ls webtool/static/css/ -alh
    total 160K
    drwxr-xr-x 2 root root 4.0K Oct 14 10:52 .
    drwxr-xr-x 7 root root 4.0K Oct 14 10:52 ..
    -rw-r--r-- 1 root root  569 Oct 14 10:52 colours.css.template
    -rw-r--r-- 1 root root 4.6K Oct 14 10:52 control-panel.css
    -rw-r--r-- 1 root root  13K Oct 14 10:52 dataset-page.css
    -rw-r--r-- 1 root root 8.7K Oct 14 10:52 explorer.css
    -rw-r--r-- 1 root root  13K Oct 14 10:52 flags.css
    -rw-r--r-- 1 root root  428 Oct 14 10:52 flowchart.css
    -rw-r--r-- 1 root root 1.2K Oct 14 10:52 jquery-jsonviewer.css
    -rw-r--r-- 1 root root  50K Oct 14 10:52 progress.css
    -rw-r--r-- 1 root root 1.1K Oct 14 10:52 reset.css
    -rw-r--r-- 1 root root 4.6K Oct 14 10:52 sigma_network.css
    -rw-r--r-- 1 root root  21K Oct 14 10:52 stylesheet.css
    

    Yksinkertaisin käytettävissä oleva ratkaisu on siis luoda oma kuva paikkaamalla nykyistä kuvaa. Käytämme tätä Dockerfile-tiedostoa:

    FROM docker.io/digitalmethodsinitiative/4cat:stable
    
    RUN chmod g+w /usr/src/app/webtool/static/css/
    RUN chmod g+w /usr/src/app/webtool/static/img/favicon/
    

    Rahti voi rakentaa sen puolestamme, jos suoritamme tämän komennon:

    $ oc new-build -D $'FROM docker.io/digitalmethodsinitiative/4cat:stable
    RUN chmod g+w /usr/src/app/webtool/static/css/\
    RUN chmod g+w /usr/src/app/webtool/static/img/favicon/' \
    --to 4cat
      --> Found container image ca4511d (8 weeks old) from docker.io for "docker.io/digitalmethodsinitiative/4cat:stable"
    
          * An image stream tag will be created as "4cat:stable" that will track the source image
          * A Docker build using a predefined Dockerfile will be created
            * The resulting image will be pushed to image stream tag "4cat:latest"
            * Every time "4cat:stable" changes a new build will be triggered
    
      --> Creating resources with label build=4cat ...
          imagestream.image.openshift.io "4cat" created
          imagestreamtag.image.openshift.io "4cat:latest" created
          buildconfig.build.openshift.io "4cat" created
      --> Success
    

    Käytimme inline Dockerfile -menetelmää, koska Dockerfile on vain 3 riviä pitkä. Hetken kuluttua meillä on uusi kuva nimeltä 4cat Rahdin sisäisessä rekisterissä. Sisäinen URL on image-registry.openshift-image-registry.svc:5000/4cat-2/4cat:latest, missä 4cat-2 on tämän dokumentaation kirjoittamiseen käyttämäni projektin nimi.

                       key: workers
                       name: env
    -          image: 'digitalmethodsinitiative/4cat:'
    +          image: 'image-registry.openshift-image-registry.svc:5000/4cat-2/4cat:latest'
               name: 4cat-frontend
               ports:
    
  7. Kun URL on vaihdettu, kaikki näyttää hyvältä 🤞. Meidän täytyy enää julkaista frontend-palvelu Internetiin:

    $ oc expose svc/frontend
    route/frontend exposed
    
    $ oc get route
    NAME       HOST/PORT                       PATH   SERVICES   PORT   TERMINATION   WILDCARD
    frontend   frontend-4cat-2.2.rahtiapp.fi          frontend   5000                 None
    

Jos vierailemme URL-osoitteessa http://frontend-4cat-2.2.rahtiapp.fi, näemme vihdoin sovelluksen.

4cat in Rahti

Yhteenveto

Kuten näet, tämän sovelluksen käyttöönotto Rahdissa oli pitkä prosessi. Käytimme kaikkia mahdollisia keinoja, mutta onnistuimme saamaan sen toimimaan Rahdissa. Toivon, että kaikki tekniikat ja perustelut ovat tässä vaiheessa sinulle selviä. Teimme joitakin uskonvaraisia hyppyjä intuition ja kokemuksen perusteella, mutta niitä on vaikea kirjoittaa paperille. Jos seuraat tätä ohjetta oman sovelluksesi kanssa ja sinulla on kysyttävää, ota rohkeasti yhteyttä osoitteeseen servicedesk@csc.fi. Ota yhteyttä myös, jos käytät jotakin muuta tekniikkaa, jota emme tässä käsittele; lisäämme sen tähän ohjeeseen.

Ohjeen lopussa sinulla pitäisi olla deploymentien YAML-tiedostot kaikkine tarvittavine muutoksineen. Yksi tapa jatkaa oppimista ja jäsentää nämä YAML-tiedostot on paketoida ne Helm chartiksi seuraamalla Helm chart -ohjettamme. Näin voit ottaa sovelluksen käyttöön useita kertoja useissa projekteissa (tuotanto, testi, kehitys, ...) yhdellä komennolla ja johdonmukaisesti.

Suomenkielinen tekoälykäännös

Sisällössä voi esiintyä virheellistä tietoa tekoälykäännöksestä johtuen.

Klikkaa tästä antaaksesi palautetta