Webbplatssökning

Hur man installerar och konfigurerar Laravel med Docker Compose på Ubuntu 22.04


Introduktion

Att containra en applikation syftar på processen att anpassa en applikation och dess komponenter för att kunna köra den i lätta miljöer som kallas containrar. Sådana miljöer är isolerade och engångsbruk, och kan användas för att utveckla, testa och distribuera applikationer till produktion.

I den här guiden kommer vi att använda Docker Compose för att containerisera en Laravel-applikation för utveckling. När du är klar kommer du att ha en demo-Laravel-applikation som körs på tre separata serviceteckningar:

  • En app-tjänst som kör PHP7.4-FPM;
  • En db-tjänst som kör MySQL 8.0;
  • En nginx-tjänst som använder app-tjänsten för att tolka PHP-kod innan Laravel-applikationen levereras till slutanvändaren.

För att möjliggöra en smidig utvecklingsprocess och underlätta felsökning av applikationen, kommer vi att hålla applikationsfilerna synkroniserade genom att använda delade volymer. Vi kommer också att se hur man använder docker compose exec-kommandon för att köra Composer och Artisan på app-containern.

Distribuera dina frontend-applikationer från GitHub med Linux-Console.net App Platform. Låt Linux-Console.net ta hand om att skala din app.

Viktiga punkter:

  • Containerisering gör utveckling förutsägbar: Att köra Laravel i Docker säkerställer konsekventa miljöer på olika datorer, tar bort problem som "det fungerar på min dator" och gör samarbete enklare.
  • Separation av tjänster förbättrar underhållbarheten: Att dela upp PHP, MySQL och Nginx i separata containrar hjälper till att isolera problem, förenklar uppdateringar och återspeglar verkliga produktionsmiljöer.
  • Miljövariabler är centrala för flexibel konfiguration: Att använda en .env-fil gör det möjligt för utvecklare att ändra databasuppgifter och andra inställningar utan att röra applikationskoden.
  • Anpassade Docker-avbilder förbättrar kontroll och säkerhet: Att bygga din egen PHP-avbild säkerställer att du bara installerar det som ditt projekt behöver, vilket håller miljön lätt och säker.
  • Filbehörigheter måste matcha behållarens användare: Att ställa in korrekt ägarskap och behörigheter för Laravels skrivbara kataloger förhindrar körtidsfel och stöder smidig lokal utveckling.
  • Att använda override-filer stöder flera miljöer: docker-compose.override.yml möjliggör lokala justeringar—som live-omladdning—utan att ändra produktionskonfigurationer. Detta håller utveckling och distribution tydligt åtskilda.
  • Felsökning börjar med att förstå containerbeteende: Att veta hur man granskar loggar, kontrollerar körande tjänster och testar anslutning är nyckeln till att snabbt lösa de flesta problem i containeriserade miljöer.
  • En Docker-baserad uppsättning skalar med ditt arbetsflöde: När den väl är byggd kan samma konfiguration driva lokala, staging- eller produktionsmiljöer, vilket skapar en stabil, återanvändbar grund för framtida Laravel-projekt.

Förutsättningar

  • Tillgång till en lokal Ubuntu-maskin eller utvecklingsserver som en icke-root-användare med sudo-behörigheter. Om du använder en fjärrserver är det rekommenderat att ha en aktiv brandvägg installerad. För att konfigurera detta, vänligen se vår guide för Initial Server Setup för Ubuntu.
  • Docker installerat på din server, följ steg 1 och 2 i Hur man installerar och använder Docker på Ubuntu.
  • Docker Compose installerat på din server, enligt Steg 1 i Hur man installerar och använder Docker Compose på Ubuntu.

Steg 1 — Skaffa demoprogrammet

För att komma igång hämtar vi demoapplikationen Laravel från dess Github-repository. Vi är intresserade av tutorial-01-grenen, som innehåller den grundläggande Laravel-applikationen vi har skapat i guiden Hur man installerar och konfigurerar Laravel med Nginx på Ubuntu 22.04 (LEMP).

För att få applikationskoden som är kompatibel med denna handledning, ladda ner version tutorial-1.0.1 till din hemkatalog med:

cd ~

curl -L https://github.com/do-community/travellist-laravel-demo/archive/tutorial-1.0.1.zip -o travellist.zip

Vi kommer att behöva kommandot unzip för att packa upp applikationskoden. Om du inte har installerat detta paket tidigare, gör det nu med:

sudo apt update

sudo apt install unzip

Nu, packa upp innehållet i applikationen och byt namn på den uppackade mappen för enklare åtkomst:

unzip travellist.zip

mv travellist-laravel-demo-tutorial-1.0.1 travellist-demo

Gå till travellist-demo-katalogen:

cd travellist-demo

I nästa steg kommer vi att skapa en .env-konfigurationsfil för att ställa in applikationen.

Steg 2 — Ställa in applikationens .env-fil

Laravel-konfigurationsfilerna finns i en katalog som kallas config, inne i applikationens rotkatalog. Dessutom används en .env-fil för att ställa in miljöberoende konfiguration, såsom inloggningsuppgifter och annan information som kan variera mellan olika distributioner. Denna fil inkluderas inte i versionskontrollen.

Varning: Konfigurationsfilen för miljön innehåller känslig information om din server, inklusive databasanvändarnamn och säkerhetsnycklar. Av den anledningen bör du aldrig dela denna fil offentligt.

Värdena som finns i .env-filen kommer att ha företräde framför värdena som är inställda i vanliga konfigurationsfiler som finns i config-katalogen. Varje installation i en ny miljö kräver en anpassad miljöfil för att definiera saker som databasanslutningsinställningar, debug-alternativ, applikationens URL samt andra saker som kan variera beroende på vilken miljö applikationen körs i.

Vi kommer nu att skapa en ny .env-fil för att anpassa konfigurationsalternativen för utvecklingsmiljön vi sätter upp. Laravel levereras med en exempel-.env-fil som vi kan kopiera för att skapa vår egen:

cp .env.example .env

Öppna den här filen med nano eller din valda textredigerare:

nano .env

Den nuvarande .env-filen från travellist-demoapplikationen innehåller inställningar för att använda en lokal MySQL-databas, med 127.0.0.1 som databashost. Vi behöver uppdatera DB_HOST-variabeln så att den pekar på den databastjänst vi kommer att skapa i vår Docker-miljö. I denna guide kommer vi att kalla vår databastjänst db. Gå vidare och ersätt det angivna värdet för DB_HOST med databastjänstens namn:

APP_NAME=Travellist
APP_ENV=dev
APP_KEY=
APP_DEBUG=true
APP_URL=http://localhost:8000

LOG_CHANNEL=stack

DB_CONNECTION=mysql
DB_HOST=db
DB_PORT=3306
DB_DATABASE=travellist
DB_USERNAME=travellist_user
DB_PASSWORD=password
...

Känn dig fri att även ändra databasnamn, användarnamn och lösenord om du vill. Dessa variabler kommer att användas i ett senare steg där vi kommer att sätta upp docker-compose.yml-filen för att konfigurera våra tjänster.

Spara filen när du är klar med redigeringen. Om du använde nano kan du göra det genom att trycka på Ctrl+x, sedan Y och Enter för att bekräfta.

Steg 3 – Konfigurera applikationens Dockerfile

Även om både våra MySQL- och Nginx-tjänster kommer att baseras på standardbilder från Docker Hub, behöver vi ändå bygga en egen bild för applikationscontainern. Vi kommer att skapa en ny Dockerfile för det.

Vår travellist-bild kommer att baseras på den officiella PHP-bilden php:7.4-fpm från Docker Hub. Ovanpå den grundläggande PHP-FPM-miljön kommer vi att installera några extra PHP-moduler och Composer-beroendehanteringsverktyget.

Vi kommer också att skapa en ny systemanvändare; detta är nödvändigt för att kunna köra artisan och composer-kommandon under utvecklingen av applikationen. uid-inställningen säkerställer att användaren inuti containern har samma uid som din systemanvändare på din värddator, där du kör Docker. På så sätt replikerats alla filer som skapas av dessa kommandon på värddatorn med korrekt behörighet. Det innebär också att du kommer kunna använda din valda kodredigerare på värddatorn för att utveckla applikationen som körs inuti containrar.

Skapa en ny Dockerfile med:

nano Dockerfile

Kopiera följande innehåll till din Dockerfile:

FROM php:7.4-fpm

# Arguments defined in docker-compose.yml
ARG user
ARG uid

# Install system dependencies
RUN apt-get update && apt-get install -y \
    git \
    curl \
    libpng-dev \
    libonig-dev \
    libxml2-dev \
    zip \
    unzip

# Clear cache
RUN apt-get clean && rm -rf /var/lib/apt/lists/*

# Install PHP extensions
RUN docker-php-ext-install pdo_mysql mbstring exif pcntl bcmath gd

# Get latest Composer
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer

# Create system user to run Composer and Artisan Commands
RUN useradd -G www-data,root -u $uid -d /home/$user $user
RUN mkdir -p /home/$user/.composer && \
    chown -R $user:$user /home/$user

# Set working directory
WORKDIR /var/www

USER $user

Glöm inte att spara filen när du är klar.

Vår Dockerfile börjar med att definiera basbilden vi använder: php:7.4-fpm.

Efter att ha installerat systempaket och PHP-tillägg installerar vi Composer genom att kopiera composer-körfilen från dess senaste officiella bild till vår egen applikationsbild.

En ny systemanvändare skapas sedan och konfigureras med hjälp av user och uid-argumenten som deklarerades i början av Dockerfilen. Dessa värden kommer att injiceras av Docker Compose vid byggtillfället.

Slutligen sätter vi standardarbetskatalogen till /var/www och byter till den nyligen skapade användaren. Detta säkerställer att du ansluter som en vanlig användare och att du är i rätt katalog när du kör composer och artisan-kommandon på applikationscontainern.

Steg 4 — Konfigurera Nginx och databasdumpfiler

När man skapar utvecklingsmiljöer med Docker Compose är det ofta nödvändigt att dela konfigurations- eller initialiseringsfiler med tjänstcontainers för att sätta upp eller starta dessa tjänster. Denna praxis underlättar att göra ändringar i konfigurationsfiler för att finjustera din miljö medan du utvecklar applikationen.

Vi kommer nu att skapa en mapp med filer som kommer att användas för att konfigurera och starta våra tjänstkontainrar.

För att ställa in Nginx kommer vi att dela en travellist.conf-fil som kommer att konfigurera hur applikationen serveras. Skapa mappen docker-compose/nginx med:

mkdir -p docker-compose/nginx

Öppna en ny fil med namnet travellist.conf i den katalogen:

nano docker-compose/nginx/travellist.conf

Kopiera följande Nginx-konfiguration till den filen:

server {
    listen 80;
    index index.php index.html;
    error_log  /var/log/nginx/error.log;
    access_log /var/log/nginx/access.log;
    root /var/www/public;
    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass app:9000;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
    }
    location / {
        try_files $uri $uri/ /index.php?$query_string;
        gzip_static on;
    }
}

Denna fil kommer att konfigurera Nginx för att lyssna på port 80 och använda index.php som standardindexsida. Den kommer att sätta dokumentroten till /var/www/public och sedan konfigurera Nginx för att använda app-tjänsten på port 9000 för att bearbeta *.php-filer.

Spara och stäng filen när du är klar med redigeringen.

För att ställa in MySQL-databasen kommer vi att dela en databassdump som importeras när containern initieras. Detta är en funktion som tillhandahålls av MySQL 8.0-bilden som vi kommer att använda på den containern.

Skapa en ny mapp för dina MySQL-initieringsfiler i docker-compose-mappen:

mkdir docker-compose/mysql

Öppna en ny .sql-fil:

nano docker-compose/mysql/init_db.sql

Följande MySQL-dump är baserad på den databas vi har skapat i vår Laravel på LEMP-guide. Den kommer att skapa en ny tabell med namnet places. Därefter kommer den att fylla tabellen med ett antal exempelplatser.

Lägg till följande kod i filen:

DROP TABLE IF EXISTS `places`;

CREATE TABLE `places` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `visited` tinyint(1) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

INSERT INTO `places` (name, visited) VALUES ('Berlin',0),('Budapest',0),('Cincinnati',1),('Denver',0),('Helsinki',0),('Lisbon',0),('Moscow',1),('Nairobi',0),('Oslo',1),('Rio',0),('Tokyo',0);

Tabellen places innehåller tre fält: id, name och visited. Fältet visited är en flagga som används för att identifiera de platser som fortfarande är att besöka. Du kan gärna ändra de exempelplatser som finns eller lägga till nya. Spara och stäng filen när du är klar.

Vi har slutfört inställningen av applikationens Dockerfile och servicekonfigurationsfiler. Nästa steg är att konfigurera Docker Compose för att använda dessa filer när vi skapar våra tjänster.

Steg 5 — Skapa en miljö med flera behållare med Docker Compose

Docker Compose gör det möjligt att skapa miljöer med flera containrar för applikationer som körs på Docker. Det använder tjänstdefinitioner för att bygga helt anpassningsbara miljöer med flera containrar som kan dela nätverk och datavolymer. Detta möjliggör en sömlös integration mellan applikationskomponenter.

För att ställa in våra servicedefinitioner skapar vi en ny fil som heter docker-compose.yml. Vanligtvis ligger denna fil i roten av applikationsmappen, och den definierar din containeriserade miljö, inklusive de basbilder du kommer att använda för att bygga dina containrar och hur dina tjänster kommer att interagera.

Vi kommer att definiera tre olika tjänster i vår docker-compose.yml-fil: app, db och nginx.

Tjänsten app kommer att bygga en bild som heter travellist, baserat på Dockerfile vi tidigare har skapat. Containern som definieras av denna tjänst kommer att köra en php-fpm-server för att tolka PHP-kod och skicka resultaten tillbaka till nginx-tjänsten, som kommer att köras på en separat container. mysql-tjänsten definierar en container som kör en MySQL 8.0-server. Våra tjänster kommer att dela ett bridgenätverk som heter travellist.

Applikationsfilerna kommer att synkroniseras på både app och nginx-tjänsterna via bind mounts. Bind mounts är användbara i utvecklingsmiljöer eftersom de möjliggör en effektiv tvåvägssynk mellan värddatorn och containrarna.

Skapa en ny docker-compose.yml-fil i rotmappen för applikationen:

nano docker-compose.yml

En typisk docker-compose.yml-fil börjar med en versionsdefinition, följt av en services-nod, under vilken alla tjänster definieras. Delade nätverk definieras vanligtvis i slutet av filen.

För att komma igång, kopiera denna mallkod till din docker-compose.yml-fil:

version: "3.9"
services:


networks:
  travellist:
    driver: bridge

Vi kommer nu att redigera services-noden för att inkludera tjänsterna app, db och nginx.

Tjänsten app

Tjänsten app kommer att sätta upp en container som heter travellist-app. Den bygger en ny Docker-image baserad på en Dockerfile som finns på samma plats som filen docker-compose.yml. Den nya imagen kommer att sparas lokalt under namnet travellist.

Även om dokumentroten som servas som applikationen ligger i nginx-containern, behöver vi applikationsfilerna någonstans inne i app-containern också, så att vi kan köra kommandoradsuppgifter med Laravel Artisan-verktyget.

Kopiera följande tjänstedefinition under din services-nod i filen docker-compose.yml:

  app:
    build:
      args:
        user: sammy
        uid: 1000
      context: ./
      dockerfile: Dockerfile
    image: travellist
    container_name: travellist-app
    restart: unless-stopped
    working_dir: /var/www/
    volumes:
      - ./:/var/www
    networks:
      - travellist

Dessa inställningar gör följande:

  • build: Denna konfiguration instruerar Docker Compose att bygga en lokal bild för app-tjänsten, med den angivna sökvägen (context) och Dockerfile för instruktioner. Argumenten user och uid injiceras i Dockerfile för att anpassa användarskapande kommandon vid byggtillfället.
  • image: Namnet som kommer att användas för bilden som byggs.
  • container_name: Ställer in container-namnet för den här tjänsten.
  • restart: Starta alltid om, såvida inte tjänsten är stoppad.
  • working_dir: Anger standardkatalogen för denna tjänst som /var/www.
  • volumes: Skapar en delad volym som kommer att synkronisera innehåll från den aktuella katalogen till /var/www inuti containern. Observera att detta inte är din dokumentrot, eftersom den kommer att finnas i nginx-containern.
  • networks: Konfigurerar denna tjänst för att använda ett nätverk med namnet travellist.

db-tjänsten

Tjänsten db använder en förbyggd MySQL 8.0-bild från Docker Hub. Eftersom Docker Compose automatiskt laddar .env-variabelfiler som ligger i samma katalog som docker-compose.yml-filen, kan vi hämta våra databasinställningar från Laravel .env-filen som vi skapade i ett tidigare steg.

Inkludera följande tjänstedefinition i din services-nod, direkt efter app-tjänsten:

  db:
    image: mysql:8.0
    container_name: travellist-db
    restart: unless-stopped
    environment:
      MYSQL_DATABASE: ${DB_DATABASE}
      MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
      MYSQL_PASSWORD: ${DB_PASSWORD}
      MYSQL_USER: ${DB_USERNAME}
      SERVICE_TAGS: dev
      SERVICE_NAME: mysql
    volumes:
      - ./docker-compose/mysql:/docker-entrypoint-initdb.d
    networks:
      - travellist

Dessa inställningar gör följande:

  • image: Definierar Docker-avbildningen som ska användas för denna container. I det här fallet använder vi en MySQL 8.0-avbildning från Docker Hub.
  • container_name: Ställer in container-namnet för den här tjänsten: travellist-db.
  • restart: Starta alltid om den här tjänsten, såvida den inte uttryckligen har stoppats.
  • environment: Definierar miljövariabler i den nya containern. Vi använder värden som hämtats från Laravel .env-filen för att konfigurera vår MySQL-tjänst, vilket automatiskt kommer att skapa en ny databas och användare baserat på de angivna miljövariablerna.
  • volumes: Skapar en volym för att dela en .sql-databasdump som kommer att användas för att initiera applikationsdatabasen. MySQL-bilden kommer automatiskt att importera .sql-filer som placeras i katalogen /docker-entrypoint-initdb.d inuti containern.
  • networks: Konfigurerar denna tjänst för att använda ett nätverk med namnet travellist.

nginx-tjänsten

Tjänsten nginx använder en färdigbyggd Nginx-bild ovanpå Alpine, en lättviktig Linux-distribution. Den skapar en container med namnet travellist-nginx, och den använder ports-definitionen för att skapa en omlänkning från port 8000 på värdsystemet till port 80 inne i containern.

Inkludera följande tjänstedefinition i din services-nod, direkt efter db-tjänsten:

  nginx:
    image: nginx:1.17-alpine
    container_name: travellist-nginx
    restart: unless-stopped
    ports:
      - 8000:80
    volumes:
      - ./:/var/www
      - ./docker-compose/nginx:/etc/nginx/conf.d
    networks:
      - travellist

Dessa inställningar gör följande:

  • image: Definierar Docker-avbildningen som ska användas för denna container. I det här fallet använder vi Alpine Nginx 1.17-avbildningen.
  • container_name: Ställer in container-namnet för den här tjänsten: travellist-nginx.
  • restart: Starta alltid om den här tjänsten, såvida den inte uttryckligen har stoppats.
  • ports: Ställer in en portar-omdirigering som möjliggör extern åtkomst via port 8000 till webbservern som körs på port 80 inuti containern.
  • volumes: Skapar två delade volymer. Den första kommer synkronisera innehållet från den aktuella katalogen till /var/www inne i containern. På så sätt, när du gör lokala ändringar i applikationsfilerna, kommer de snabbt att återspeglas i applikationen som körs av Nginx inne i containern. Den andra volymen säkerställer att vår Nginx-konfigurationsfil, som finns på docker-compose/nginx/travellist.conf, kopieras till containerns Nginx-konfigurationsmapp.
  • networks: Konfigurerar denna tjänst att använda ett nätverk med namnet travellist.

Färdig docker-compose.yml-fil

Så här ser vår färdiga docker-compose.yml-fil ut:

version: "3.9"
services:
  app:
    build:
      args:
        user: sammy
        uid: 1000
      context: ./
      dockerfile: Dockerfile
    image: travellist
    container_name: travellist-app
    restart: unless-stopped
    working_dir: /var/www/
    volumes:
      - ./:/var/www
    networks:
      - travellist

  db:
    image: mysql:8.0
    container_name: travellist-db
    restart: unless-stopped
    environment:
      MYSQL_DATABASE: ${DB_DATABASE}
      MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
      MYSQL_PASSWORD: ${DB_PASSWORD}
      MYSQL_USER: ${DB_USERNAME}
      SERVICE_TAGS: dev
      SERVICE_NAME: mysql
    volumes:
      - ./docker-compose/mysql:/docker-entrypoint-initdb.d
    networks:
      - travellist

  nginx:
    image: nginx:1.17-alpine
    container_name: travellist-nginx
    restart: unless-stopped
    ports:
      - 8000:80
    volumes:
      - ./:/var/www
      - ./docker-compose/nginx:/etc/nginx/conf.d/
    networks:
      - travellist

networks:
  travellist:
    driver: bridge

Se till att du sparar filen när du är klar.

Steg 6 — Köra applikationen med Docker Compose

Vi kommer nu att använda docker compose-kommandon för att bygga applikationsbilden och köra de tjänster vi specificerade i vår uppsättning.

Bygg app-bilden med följande kommando:

docker compose build app

Det här kommandot kan ta några minuter att slutföra. Du kommer att se en liknande utdata:

Building app
Sending build context to Docker daemon  377.3kB
Step 1/11 : FROM php:7.4-fpm
 ---> 8c08d993542f
Step 2/11 : ARG user
 ---> e3ce3af04d87
Step 3/11 : ARG uid
 ---> 30cb921ef7df
Step 4/11 : RUN apt-get update && apt-get install -y     git     curl     libpng-dev     libonig-dev     libxml2-dev     zip     unzip
. . .
 ---> b6dbc7a02e95
Step 5/11 : RUN apt-get clean && rm -rf /var/lib/apt/lists/*
 ---> 10ef9dde45ad
. . .
Step 6/11 : RUN docker-php-ext-install pdo_mysql mbstring exif pcntl bcmath gd
. . .
 ---> 920e4f09ec75
Step 7/11 : COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
 ---> dbbcd44e44af
Step 8/11 : RUN useradd -G www-data,root -u $uid -d /home/$user $user
 ---> db98e899a69a
Step 9/11 : RUN mkdir -p /home/$user/.composer &&     chown -R $user:$user /home/$user
 ---> 5119e26ebfea
Step 10/11 : WORKDIR /var/www
 ---> 699c491611c0
Step 11/11 : USER $user
 ---> cf250fe8f1af
Successfully built cf250fe8f1af
Successfully tagged travellist:latest

När bygget är klart kan du köra miljön i bakgrundsläge med:

docker compose up -d
Creating travellist-db    ... done
Creating travellist-app   ... done
Creating travellist-nginx ... done

Detta kommer att köra dina containrar i bakgrunden. För att visa information om tillståndet på dina aktiva tjänster, kör:

docker compose ps

Du kommer att se ett resultat som detta:

      Name                    Command              State                  Ports                
-----------------------------------------------------------------------------------------------
travellist-app     docker-php-entrypoint php-fpm   Up      9000/tcp                            
travellist-db      docker-entrypoint.sh mysqld     Up      3306/tcp, 33060/tcp                 
travellist-nginx   nginx -g daemon off;            Up      0.0.0.0:8000->80/tcp,:::8000->80/tcp

Din miljö är nu igång.

Du kan nu verifiera att varje containeriserad tjänst svarar korrekt genom att använda enkla curl-kommandon.

  1. För att testa Nginx-webbtjänsten:

    curl -I http://localhost:8000

    Förväntad utdata:

    HTTP/1.1 200 OK
    Server: nginx/1.17.10
    Content-Type: text/html; charset=UTF-8

    Detta bekräftar att Nginx-containern körs och levererar svar från din Laravel-applikation.

  2. För att testa PHP-FPM genom Nginx:

    curl -s http://localhost:8000 | grep "Berlin"

    Om applikationen körs korrekt returnerar detta kommando välkomstsidan i HTML som innehåller ordet Berlin.

Vi behöver fortfarande köra några kommandon för att slutföra installationen av applikationen. Du kan använda kommandot docker compose exec för att köra kommandon i tjänstbehållarna, till exempel ls -l för att visa detaljerad information om filer i applikationskatalogen:

docker compose exec app ls -l
total 256
-rw-r--r-- 1 sammy sammy    737 Apr 18 14:21 Dockerfile
-rw-r--r-- 1 sammy sammy    101 Jan  7  2020 README.md
drwxr-xr-x 6 sammy sammy   4096 Jan  7  2020 app
-rwxr-xr-x 1 sammy sammy   1686 Jan  7  2020 artisan
drwxr-xr-x 3 sammy sammy   4096 Jan  7  2020 bootstrap
-rw-r--r-- 1 sammy sammy   1501 Jan  7  2020 composer.json
-rw-r--r-- 1 sammy sammy 179071 Jan  7  2020 composer.lock
drwxr-xr-x 2 sammy sammy   4096 Jan  7  2020 config
drwxr-xr-x 5 sammy sammy   4096 Jan  7  2020 database
drwxr-xr-x 4 sammy sammy   4096 Apr 18 14:22 docker-compose
-rw-r--r-- 1 sammy sammy   1017 Apr 18 14:29 docker-compose.yml
-rw-r--r-- 1 sammy sammy   1013 Jan  7  2020 package.json
-rw-r--r-- 1 sammy sammy   1405 Jan  7  2020 phpunit.xml
drwxr-xr-x 2 sammy sammy   4096 Jan  7  2020 public
-rw-r--r-- 1 sammy sammy    273 Jan  7  2020 readme.md
drwxr-xr-x 6 sammy sammy   4096 Jan  7  2020 resources
drwxr-xr-x 2 sammy sammy   4096 Jan  7  2020 routes
-rw-r--r-- 1 sammy sammy    563 Jan  7  2020 server.php
drwxr-xr-x 5 sammy sammy   4096 Jan  7  2020 storage
drwxr-xr-x 4 sammy sammy   4096 Jan  7  2020 tests
-rw-r--r-- 1 sammy sammy    538 Jan  7  2020 webpack.mix.js

Vi kommer nu att köra composer install för att installera applikationens beroenden:

docker compose exec app rm -rf vendor composer.lock

docker compose exec app composer install

Du kommer att se ett resultat som detta:

No composer.lock file present. Updating dependencies to latest instead of installing from lock file. See https://getcomposer.org/install for more information.
. . .
Lock file operations: 89 installs, 0 updates, 0 removals
  - Locking doctrine/inflector (2.0.4)
  - Locking doctrine/instantiator (1.4.1)
  - Locking doctrine/lexer (1.2.3)
  - Locking dragonmantank/cron-expression (v2.3.1)
  - Locking egulias/email-validator (2.1.25)
  - Locking facade/flare-client-php (1.9.1)
  - Locking facade/ignition (1.18.1)
  - Locking facade/ignition-contracts (1.0.2)
  - Locking fideloper/proxy (4.4.1)
  - Locking filp/whoops (2.14.5)
. . .
Writing lock file
Installing dependencies from lock file (including require-dev)
Package operations: 89 installs, 0 updates, 0 removals
  - Downloading doctrine/inflector (2.0.4)
  - Downloading doctrine/lexer (1.2.3)
  - Downloading dragonmantank/cron-expression (v2.3.1)
  - Downloading symfony/polyfill-php80 (v1.25.0)
  - Downloading symfony/polyfill-php72 (v1.25.0)
  - Downloading symfony/polyfill-mbstring (v1.25.0)
  - Downloading symfony/var-dumper (v4.4.39)
  - Downloading symfony/deprecation-contracts (v2.5.1)
. . .
Generating optimized autoload files
> Illuminate\Foundation\ComposerScripts::postAutoloadDump
> @php artisan package:discover --ansi
Discovered Package: facade/ignition
Discovered Package: fideloper/proxy
Discovered Package: laravel/tinker
Discovered Package: nesbot/carbon
Discovered Package: nunomaduro/collision
Package manifest generated successfully.

Det sista vi behöver göra innan vi testar applikationen är att generera en unik applikationsnyckel med artisan Laravel-kommandoradsverktyget. Denna nyckel används för att kryptera användarsessioner och annan känslig data:

docker compose exec app php artisan key:generate
Application key set successfully.

Gå nu till din webbläsare och öppna din servers domännamn eller IP-adress på port 8000:

http://server_domain_or_IP:8000

Observera: Om du kör denna demo på din lokala dator, använd http://localhost:8000 för att komma åt applikationen från din webbläsare.

Du kommer att se en sida som den här:

Du kan också testa Laravel-applikationen från insidan av app-behållaren utan att använda en webbläsare:

docker compose exec app curl http://nginx

Om allt är korrekt konfigurerat bör du se HTML-utdata från Laravels standard välkomstsida.

<html>
<head>
    <title>Travel List</title>
</head>

<body>
    <h1>My Travel Bucket List</h1>
    <h2>Places I'd Like to Visit</h2>
    <ul>
        <li>Berlin</li>
        <li>Budapest</li>
        <li>Denver</li>
        <li>Helsinki</li>
        <li>Lisbon</li>
        <li>Nairobi</li>
        <li>Rio</li>
        <li>Tokyo</li>
    </ul>

    <h2>Places I've Already Been To</h2>
    <ul>
        <li>Cincinnati</li>
        <li>Moscow</li>
        <li>Oslo</li>
    </ul>
</body>
</html>

Du kan använda kommandot logs för att kontrollera loggarna som genereras av dina tjänster:

docker compose logs nginx
Attaching to travellist-nginx
. . .
travellist-nginx | 172.24.9.1 - - [18/Apr/2022:14:49:16 +0000] "GET / HTTP/1.1" 200 627 "-" "curl/7.82.0"
travellist-nginx | 172.24.9.1 - - [18/Apr/2022:14:51:27 +0000] "GET / HTTP/1.1" 200 627 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:89.0) Gecko/20100101 Firefox/89.0"
travellist-nginx | 172.24.9.1 - - [18/Apr/2022:14:51:27 +0000] "GET /favicon.ico HTTP/1.1" 200 0 "http://localhost:8000/" "Mozilla/5.0 (X11; Linux x86_64; rv:89.0) Gecko/20100101 Firefox/89.0"

Du kan också använda följande curl-kommando för att utlösa loggposter:

curl http://localhost:8000

Kör sedan igen:

docker compose logs nginx

Du bör nu se en matchande åtkomstloggpost för din förfrågan.

Om du vill pausa din Docker Compose-miljö samtidigt som du behåller tillståndet för alla dess tjänster, kör:

docker compose pause
Pausing travellist-db    ... done
Pausing travellist-nginx ... done
Pausing travellist-app   ... done

Du kan sedan återuppta dina tjänster med:

docker compose unpause
Unpausing travellist-app   ... done
Unpausing travellist-nginx ... done
Unpausing travellist-db    ... done

För att stänga ner ditt Docker Compose-miljö och ta bort alla dess containers, nätverk och volymer, kör:

docker compose down
Stopping travellist-nginx ... done
Stopping travellist-db    ... done
Stopping travellist-app   ... done
Removing travellist-nginx ... done
Removing travellist-db    ... done
Removing travellist-app   ... done
Removing network travellist-laravel-demo_travellist

För en översikt över alla Docker Compose-kommandon, vänligen se Docker Compose-kommandoreferensen.

Fixa fil- och katalogbehörigheter i Laravel

När man kör Laravel i Docker-containrar är ett av de vanligaste problemen som utvecklare stöter på relaterat till fil- och katalogbehörigheter. Laravel kräver att vissa kataloger är skrivbara av PHP-FPM-processen inuti app-containern. Om dessa kataloger inte är skrivbara kan applikationen misslyckas med att logga fel, cachelagra konfigurationsfiler eller lagra sessionsdata korrekt.

Du kan stöta på meddelanden som:

The stream or file "/var/www/storage/logs/laravel.log" could not be opened in append mode: failed to open stream: Permission denied

eller

file_put_contents(/var/www/bootstrap/cache/config.php): Failed to open stream: Permission denied

Dessa fel indikerar att användaren som kör PHP inom containern inte har behörighet att skriva till de nödvändiga katalogerna.

Följande steg beskriver hur man diagnostiserar och åtgärdar dessa problem i både lokala och produktionsmiljöer.

Justera skrivbara katalogbehörigheter

Laravel kräver att två kataloger är skrivbara av webbserverns användare:

  • /var/www/storage
  • /var/www/bootstrap/cache

Om du ser behörighetsfel kan du åtgärda dem genom att justera ägarskap och behörigheter inifrån containern:

docker compose exec app chown -R sammy:sammy /var/www/storage /var/www/bootstrap/cache

docker compose exec app chmod -R 775 /var/www/storage /var/www/bootstrap/cache

Om din Dockerfile använder ett annat användarnamn (bestämt genom user-byggargumentet), ersätt sammy med det användarnamnet.

Du kan verifiera äganderätten med följande kommando:

docker compose exec app ls -ld /var/www/storage /var/www/bootstrap/cache

Utdata bör visa att användaren och gruppen matchar PHP-FPM-processen inuti containern.

Om du istället vill justera behörigheter från värddatorn, kör:

sudo chown -R $(id -u):$(id -g) storage bootstrap/cache

sudo chmod -R 775 storage bootstrap/cache

Detta säkerställer att båda Laravel-katalogerna är skrivbara av både containern och din värdanvändare.

Ställ in katalogägarskap under bildbyggnad

För att förhindra att behörighetsproblem återkommer efter varje ny byggnad kan du ställa in katalogägarskap under Docker-bildens byggprocess. Öppna din Dockerfile och lägg till följande rad mot slutet, innan du byter till den icke-root användaren:

RUN chown -R $user:www-data /var/www

Detta kommando säkerställer att alla filer och kataloger under /var/www ägs av den användare du definierade i din Dockerfile.

För en mer riktad och säker metod kan du justera endast de kataloger som Laravel behöver skriva till:

RUN chown -R $user:www-data /var/www/storage /var/www/bootstrap/cache

Efter att ha gjort denna ändring, bygg om bilden och starta om containrarna:

docker compose build app

docker compose up -d

Nästa gång containern startar kommer den redan att ha rätt behörigheter.

Verifiera användar-ID:s konsistens mellan värd och container

När du använder bind mounts delar Docker filer mellan din värd och din container. Om värdbrukarens numeriska UID skiljer sig från UID som är definierad i containern kan konflikter med filägarskap uppstå. Detta är vanligt på system där användar-ID:n varierar mellan maskiner.

För att kontrollera UID-värdena, kör:

id -u $(whoami)

docker compose exec app id -u

Om dessa två siffror inte stämmer överens, uppdatera din docker-compose.yml-fil för att skicka ditt faktiska UID till byggprocessen:

build:
  args:
    user: sammy
    uid: 1000

Bygg sedan om bilden:

docker compose build app

docker compose up -d

Detta säkerställer att containeranvändaren matchar din värdanvändare, vilket förhindrar behörighetsproblem på bindmonterade filer.

Åtgärda behörigheter för Composer-cachekatalogen

Composer lagrar nedladdade beroenden och cache-filer i användarens hemkatalog inne i containern (/home/sammy/.composer). Om denna katalog inte är skrivbar kan du se varningar som:

Cannot create cache directory /home/sammy/.composer/cache

Du kan åtgärda detta genom att skapa cachens katalog och tilldela korrekt ägarskap:

docker compose exec app mkdir -p /home/sammy/.composer/cache

docker compose exec app chown -R sammy:sammy /home/sammy/.composer

Detta säkerställer att Composer kan lagra beroenden och cachefiler utan behörighetsfel, vilket också gör framtida composer install-körningar snabbare.

Rekommenderade metoder för produktionsmiljöer

I produktion bör behörighetshantering hanteras under bildbyggnaden istället för vid körning. Detta förbättrar konsekvens och säkerhet.

Följ dessa metoder för en produktionsklar konfiguration:

  • Undvik bind mounts för applikationskod: Kopiera istället applikationsfilerna till bilden under byggprocessen. Bind mounts bör reserveras för utveckling.

  • Ställ in behörigheter under byggnation: Lägg till RUN chown och chmod kommandon i din Dockerfile för att säkerställa korrekt ägarskap och åtkomsträttigheter innan distribution.

  • Använd den användare med minst privilegier: Se till att PHP-processen körs under en icke-root användare (den nuvarande inställningen med $user gör redan detta).

  • Begränsa behörigheter på skrivskyddade kataloger: De flesta applikationsfiler bör vara skrivskyddade. Du kan säkerställa detta med:

    chmod -R 755 /var/www
    
    chmod -R 775 /var/www/storage /var/www/bootstrap/cache

    Denna inställning gör det möjligt för Laravel att skriva endast där det är nödvändigt samtidigt som andra applikationsfiler skyddas från ändring.

Genom att följa dessa steg kommer dina Laravel-containrar att ha stabila och förutsägbara filbehörigheter både i lokala och produktionsmiljöer. Detta minskar återkommande fel och säkerställer att Laravel kan logga data, cache:a filer och skriva sessioner pålitligt.

Förstå docker-compose.override.yml för lokala och produktionsmiljöer

Docker Compose låter dig definiera applikationer med flera containrar med en enda konfigurationsfil. I de flesta fall lagras denna konfiguration i en fil som heter docker-compose.yml. Att hantera flera miljöer, såsom lokal utveckling och produktion, kräver dock ofta miljöspecifika justeringar. Det är här filen docker-compose.override.yml blir användbar.

Som standard söker Docker Compose automatiskt efter en fil med namnet docker-compose.override.yml i samma katalog som bas-Compose-filen. När den hittas slås konfigurationerna från båda filerna samman när du kör någon docker compose-kommando. Denna metod gör det möjligt för utvecklare att behålla en ren, återanvändbar baskonfiguration samtidigt som de kan anpassa specifika delar av uppsättningen för lokal eller produktionsanvändning.

Roll av docker-compose.override.yml

Filen docker-compose.override.yml är en utökning av den grundläggande Compose-konfigurationen. Den ändrar eller lägger till egenskaper som endast gäller för en viss miljö, utan att kräva ändringar i huvudfilen docker-compose.yml. Override-filen är särskilt användbar i lokala utvecklingsarbetsflöden, där utvecklare ofta behöver montera källkod, aktivera felsökningsverktyg eller ändra miljövariabler för testning.

När du kör kommandot docker compose up sammanfogar Docker automatiskt innehållet i docker-compose.yml och docker-compose.override.yml. Om en tjänst, volym eller konfiguration är definierad i båda filerna har värdena i överstyrningsfilen företräde.

För att använda en annan override-fil, till exempel en avsedd för produktion, kan du ange filen manuellt med -f-flaggan:

docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d

Detta tillvägagångssätt gör att du kan behålla separata konfigurationer för olika miljöer samtidigt som du använder en enhetlig kommandostruktur.

Strukturering för lokal utveckling

Lokala utvecklingsmiljöer kräver vanligtvis frekventa ändringar, live-kodladdning och utförlig loggning. Filen docker-compose.override.yml gör det möjligt att införa dessa funktioner utan att påverka andra miljöer.

En typisk lokal åsidosättningsfil kan innehålla:

  • Bindmonteringar för live-uppdateringar av kod
  • Lokala bygginstruktioner istället för att använda förbyggda bilder
  • Utvecklingsspecifika miljövariabler
  • Felsöknings- och testtjänster

Till exempel:

version: "3.9"

services:
  app:
    build:
      context: .
      dockerfile: Dockerfile.dev
    volumes:
      - ./src:/app
      - ./logs:/app/logs
    environment:
      - DATABASE_URL=postgres://postgres:postgres@db:5432/app_db
      - LOG_LEVEL=debug
    ports:
      - "8000:8000"
    depends_on:
      - db

  db:
    environment:
      - POSTGRES_PASSWORD=postgres

I det här exemplet:

  • Tjänsten app byggs direkt från en lokal Dockerfile (Dockerfile.dev), vilket gör det enkelt att testa ändringar utan att behöva bygga om bilder via ett register.
  • Källkoden monteras med bindmonteringar, vilket gör att containern speglar lokala filändringar i realtid.
  • Miljövariabler såsom LOG_LEVEL=debug sätts för att ge mer detaljerad information under utveckling.
  • Databasen använder enkla autentiseringsuppgifter som är lämpliga för lokal testning men inte bör användas i produktion.

Denna konfiguration ger en snabbare och mer flexibel utvecklingsmiljö samtidigt som baskonfigurationen förblir oförändrad.

Förberedelser för produktion

Produktionsmiljöer kräver stabilitet, reproducerbarhet och säkerhet. Containrar bör köras från förbyggda bilder istället för att byggas lokalt, och känslig information bör hanteras på ett säkert sätt. Till skillnad från den automatiskt tillämpade överskrivningsfilen som används för lokal utveckling, måste produktionsöverskrivningar specificeras uttryckligen.

En produktionsöverskridande fil (docker-compose.prod.yml) är vanligtvis utformad för att ersätta lokala byggsteg med bildreferenser, använda namngivna volymer istället för bindningsmonteringar och definiera distributionsrelaterade egenskaper såsom resursgränser och skalning.

Exempel:

version: "3.9"

services:
  app:
    image: registry.example.com/myapp:1.2.3
    environment:
      - DATABASE_URL=${DATABASE_URL}
      - LOG_LEVEL=info
    volumes:
      - app-data:/var/lib/app
    ports:
      - "8000:8000"
    restart: unless-stopped
    deploy:
      replicas: 3
      resources:
        limits:
          cpus: "0.5"
          memory: 512M

  db:
    image: postgres:15
    volumes:
      - db-data:/var/lib/postgresql/data
    environment:
      - POSTGRES_PASSWORD_FILE=/run/secrets/db_password

secrets:
  db_password:
    external: true

volumes:
  app-data:
  db-data:

I denna konfiguration:

  • Tjänsten app refererar till en förbyggd bild (myapp:1.2.3) som lagras i ett register istället för att byggas lokalt.

  • Bind-mounts ersätts med namngivna volymer för att säkerställa konsekvent och isolerad datalagring.

  • Känsliga referenser lagras säkert med Docker-hemligheter.

  • Avsnittet deploy definierar skalningsbeteende och resursbegränsningar för bättre stabilitet under belastning.

  • Konfigurationen måste tillämpas uttryckligen under distributionen:

    docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d

Denna struktur säkerställer att produktionsdistributioner är konsekventa, kontrollerade och fria från lokala utvecklingsartefakter.

Jämförelse av lokala och produktionsöverskridanden

KonfigurationsaspektLokal (docker-compose.override.yml)Produktion (docker-compose.prod.yml)
Tillämpas automatisktJaNej (måste använda -f)
KällkodshanteringBind-mounts för direkta uppdateringarFörbyggda bilder från registret
MiljövariablerUtvecklarfokuserade värderingarProduktionssäkra värden
LoggningDetaljerad (debug)Koncis (info eller error)
Hantering av hemligheterVanliga värden eller .envDocker-hemligheter eller hanterade hemligheter
SkalningEnkel behållareFlera kopior
PrestandaoptimeringInte nödvändigtResursgränser definierade
FelsökningsverktygAktiveradInaktiverad
Starta om-policyManuell eller ingen
restart: unless-stopped

Att använda flera Docker Compose-filer ger ett smidigt sätt att separera miljöspecifika konfigurationer från grundinställningarna. Basfilen docker-compose.yml definierar den gemensamma applikationsstrukturen, medan docker-compose.override.yml anpassar den för lokal utveckling. Vid distribution till produktion säkerställer en specifik override-fil en förutsägbar och säker konfiguration.

Detta mönster gör det möjligt för team att upprätthålla ett konsekvent arbetsflöde. Utvecklare kan starta applikationen lokalt med:

docker compose up

och distribuera till produktion med:

docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d

Båda miljöerna delar samma kärnkonfiguration samtidigt som de har oberoende inställningar som är lämpliga för deras specifika krav. Denna separation förbättrar underhållet, minskar konfigurationsfel och håller lokala och produktionsmiljöer i linje med varandra.

Felsökning av din miljö

Den här sektionen ger felsökningssteg för vanliga problem som du kan stöta på när du kör din app med Docker Compose.

502 Bad Gateway (Nginx visar 502-svar)

Symtom:

  • Webbläsaren visar 502 Bad Gateway när du försöker komma åt http://localhost:8000.
  • Nginx-loggar innehåller rader som recv() failed (111: Connection refused) eller connect() failed (111: Connection refused) while connecting to upstream.

Möjliga orsaker:

  • PHP-FPM (tjänsten app) körs inte eller lyssnar inte på den förväntade socketen/porten.
  • Nginx fastcgi_pass pekar på fel värd/port.
  • Containernamn stämmer inte eller nätverksproblem mellan nginx och app.
  • app kraschade vid start (t.ex. på grund av saknade tillägg eller konfigurationsfel).

Hur man bekräftar:

  1. Granska Nginx-loggar:

    docker compose logs nginx | tail -n 100

    Sök efter 502-meddelanden eller fel i upstream-anslutningen.

  2. Kontrollera status och loggar för app-containern:

    docker compose ps app
    
    docker compose logs app --tail=200
  3. Bekräfta att PHP-FPM lyssnar inne i app-containern:

    docker compose exec app ss -ltnp | grep :9000 || docker compose exec app ss -lxp | grep php-fpm

    Förväntat: antingen en TCP-lyssnare på port 9000 eller en Unix-socket som används av nginx (mindre vanligt med denna compose).

  4. Bekräfta att nginx kan lösa och nå app på compose-nätverket:

    docker compose exec nginx ping -c 2 app
    
    docker compose exec nginx wget -qO- --timeout=2 http://app:9000/ || true

    Om ping misslyckas eller wget går ut på tiden, finns det ett nätverksproblem eller en skillnad i tjänstens namn.

Vanliga åtgärder:

  • Om PHP-FPM inte körs, kontrollera app-loggarna för allvarliga PHP-fel eller startproblem. Åtgärda det underliggande felet (ofta saknad tillägg eller behörighetsproblem) och starta om:

    docker compose restart app
    
    docker compose logs app --tail=100
  • Om Nginx-konfigurationen använder en annan upstream (t.ex. fastcgi_pass 127.0.0.1:9000;), uppdatera docker-compose/nginx/travellist.conf till fastcgi_pass app:9000; (som matchar ditt compose-tjänstnamn) och ladda om Nginx:

    # After editing config in host
    
    docker compose exec nginx nginx -s reload
    
    docker compose logs nginx --tail=50
  • Om PHP-FPM lyssnar på en Unix-socket (t.ex. /run/php/php7.4-fpm.sock) men Nginx förväntar sig TCP eller vice versa, standardisera till TCP app:9000 för Compose-konfigurationer eller montera sockeln korrekt mellan containrarna (rekommenderas: använd TCP i multi-container Compose).

Saknade PHP-tillägg (fel vid körning av Composer eller Artisan, eller fel vid körning)

Symtom:

  • Composer- eller Laravel-kommandon misslyckas med meddelanden som Class "PDO" not found, ext-pdo is missing eller Call to undefined function json_encode.
  • PHP-fel i app-loggar som refererar till odefinierade klasser eller funktioner.

Hur man bekräftar:

  1. Inspektera app-behållarens lista över PHP-moduler:

    docker compose exec app php -m | sort

    Sök efter de tilläggsnamn du behöver (för typiska Laravel-tillägg: pdo_mysql, mbstring, bcmath, openssl, tokenizer, xml, ctype, json, gd).

  2. Kontrollera Composer-feltexten som vanligtvis anger vilka tillägg som krävs:

    docker compose exec app composer install

Åtgärder:

  • Lägg till saknade tillägg i din Dockerfile och bygg om bilden. Exempel (för pdo_mysql och gd):

    RUN apt-get update && apt-get install -y libpng-dev libxml2-dev \
        && docker-php-ext-install pdo_mysql mbstring xml gd

    Bygg om och starta om:

    docker compose build app
    
    docker compose up -d app
    
    docker compose logs app --tail=100
  • Om en tillägg kräver systembibliotek (till exempel gd behöver libpng-dev), lägg till motsvarande apt-get install-rader före docker-php-ext-install.

  • Om du behöver en PHP-tillägg som inte är inbyggd, överväg att installera den via PECL och aktivera den i php.ini.

Databasanslutningsfel (Laravel kan inte ansluta till MySQL)

Symtom:

  • Laravel visar databasanslutningsfel (SQLSTATE[HY000] [2002] Connection refused eller Access denied for user).
  • Migrationer misslyckas, eller så visar applikationen en tom sida för datadrivna sidor.

Hur man bekräftar:

  1. Kontrollera DB-behållarens loggar för initialiseringsfel:

    docker compose logs db --tail=200
  2. Verifiera att DB-behållaren är igång:

    docker compose ps db
  3. Bekräfta att referenser och värd är konsekventa mellan .env och docker-compose.yml. I Laravels .env ska DB_HOST vara namnet på compose-tjänsten (db), inte 127.0.0.1 eller localhost:

    DB_HOST=db
    DB_PORT=3306
    DB_DATABASE=travellist
    DB_USERNAME=travellist_user
    DB_PASSWORD=password
  4. Test från insidan av db-containern:

    docker compose exec db mysql -u"${DB_USERNAME}" -p"${DB_PASSWORD}" -e "SHOW DATABASES;"

    Eller, testa från app-containern för att säkerställa nätverksanslutning:

    docker compose exec app sh -c 'which mysql >/dev/null 2>&1 || echo "no mysql client"; mysql -h db -u"${DB_USERNAME}" -p"${DB_PASSWORD}" -e "SELECT VERSION();"'

Vanliga orsaker och lösningar:

  • Fel värd i .env: uppdatera DB_HOST=db, återskapa containrar eller ladda om miljövariabler:

    docker compose down
    
    docker compose up -d
    
    docker compose exec app php artisan migrate
  • Databasen är inte redo när appen startar: använd en återförsöksmekanism i din app eller lägg till en hälsokontroll och börja beställningen. Du kan också vänta manuellt:

    docker compose exec db mysqladmin -u"${DB_USERNAME}" -p"${DB_PASSWORD}" ping
    
    # expected: mysqld is alive
  • Initierings-SQL misslyckades: kontrollera filer under ./docker-compose/mysql, ett syntax- eller behörighetsfel kan avbryta DB-initiering. Kontrollera DB-loggar för importfel.

  • Behörigheter/felaktiga uppgifter: bekräfta att databasen och användaren finns. Skapa om databasen eller kör SQL för att ge behörigheter.

  • Användning av portar på värdnivå: om du försökte curl telnet://localhost:3306 och db-tjänsten inte exponerar en värdport, kommer den anslutningen att nekas enligt design. Testa inifrån containrar, eller exponera porten i docker-compose.yml (ports: - "3306:3306") för felsökning som endast är lokal.

Behörighets- och filsystemproblem (lagring, cache, loggfiler)

Symtom:

  • Laravel kastar undantag relaterade till att skriva cache eller loggar: Strömmen eller filen "/var/www/storage/logs/laravel.log" kunde inte öppnas.
  • Filer som skapas av containerprocesser ägs av root och kan inte skrivas till av din värdanvändare.

Hur man bekräftar:

  1. Kontrollera filbehörigheter från värden:

    ls -l
    
    ls -l storage bootstrap/cache
    
    docker compose exec app id -u   # user id inside container
  2. Kontrollera behållarloggar för behörighetsfel.

Åtgärder:

  • Se till att Dockerfilen anger användaren och UID som matchar din värdanvändare (din Dockerfile skapar redan en användare med ARG uid). Bekräfta att uid i docker-compose.yml build-args matchar din värd-UID (vanligtvis 1000).

  • Fixa ägarskap från värden eller inuti containern:

    docker compose exec app chown -R sammy:sammy /var/www/storage /var/www/bootstrap/cache

    eller från värden:

    sudo chown -R $(id -u):$(id -g) storage bootstrap/cache
  • För utveckling kan bind-mounts orsaka behörighetsproblem; det är bättre att köra containerkommandon för att justera äganderätten efter att containrarna startats.

Kompositör- eller leverantörsrelaterade fel

Symtom:

  • composer install misslyckas inuti app eller om vendor-mappen saknas, vilket orsakar att klassen inte hittas.
  • composer rapporterar minnesbrist i containern.

Hur man bekräftar:

  • Kör composer inuti app-containern och fånga upp utdata:

    docker compose exec app composer install --no-interaction --prefer-dist

Åtgärder:

  • Om composer-minnesgränser nås, tillåt mer minne eller sätt miljövariabeln för composer:

    docker compose exec app php -d memory_limit=-1 /usr/bin/composer install
  • Se till att Composer-exekverbara filen finns (din Dockerfile kopierar composer). Om inte, bygg om bilden med composer-lagret.

  • Om vendor saknas på grund av bind mount-overlay, se till att din bind mount inte döljer vendor-mappen som skapats i bilden. Bästa praxis är att köra composer install efter att containrarna har startat så att vendor skapas i den monterade mappen, eller lägg till vendor i containern via image-byggnad för produktion.

Applikationen visar en tom sida eller 500-fel

Symtom:

  • Webbläsaren visar tomt svar eller HTTP 500.
  • Nginx-loggar visar 200 men sidan är tom; app-loggar visar fatala undantag.

Hur man bekräftar:

  • Granska applikationsloggar:

    docker compose exec app tail -n 200 storage/logs/laravel.log
    
    docker compose logs app --tail=200
  • Kontrollera miljön: APP_DEBUG=true i .env gör att Laravel visar detaljerade fel under utveckling (aktivera inte i produktion).

Åtgärder:

  • Åtgärda det underliggande undantaget som visas i laravel.log.

  • Se till att .env finns och att APP_KEY är inställt:

    docker compose exec app php artisan key:generate
  • Kör migrationer, rensa cache:

    docker compose exec app php artisan migrate --force
    
    docker compose exec app php artisan config:cache
    
    docker compose exec app php artisan route:cache
    
    docker compose exec app php artisan view:cache

Misslyckade containerbyggen (fel under docker compose build)

Symtom:

  • docker compose build misslyckas med fel vid apt eller byggsteg.

Hur man bekräftar:

  • Kör om byggnaden med loggar:

    docker compose build app

Åtgärder:

  • Läs utdata från det misslyckade steget. Vanliga problem:

    • Nätverk/DNS i byggmiljön: försök igen eller se till att Docker kan komma åt internet.
    • Saknade paket eller fel apt-källa: lägg till apt-get update innan installationer och rensa apt-listorna efteråt.
    • Behörigheter på filer som kopieras in i bilden: säkerställ korrekta COPY-vägar.

Exempel på Dockerfile-avsnitt för robusta installationer:

RUN apt-get update && apt-get install -y --no-install-recommends \
    libpng-dev libxml2-dev zip unzip \
  && docker-php-ext-install pdo_mysql mbstring xml gd \
  && apt-get clean && rm -rf /var/lib/apt/lists/*

Nätverks- eller DNS-problem mellan behållare

Symtom:

  • En container kan inte nå en annan via servicenamn (t.ex. kan app inte nå db med db:3306).
  • ping med servicens namn misslyckas.

Hur man bekräftar:

docker compose exec app ping -c 3 db

docker compose exec app getent hosts db

docker network inspect travellist

Åtgärder:

  • Bekräfta att tjänster delar samma nätverk i docker-compose.yml (båda bör referera till travellist).

  • Om du ändrade tjänstenamn eller nätverksnamn, uppdatera DB_HOST och Nginx upstreams därefter.

  • Återskapa nätverk (detta förstör temporära containrar, så var försiktig):

    docker compose down
    
    docker network prune   # optional and destructive
    
    docker compose up -d

Användbara diagnostiska kommandon

Kör dessa för riktad inspektion:

  • Visa körande containrar och portar:

    docker compose ps
  • Visa loggar för en tjänst:

    docker compose logs -f --tail=200 nginx
  • Kör ett skal inuti en container:

    docker compose exec app sh
    
    docker compose exec db bash
  • Inspektera miljövariabler för containern:

    docker compose exec app env | sort
    
    docker compose exec db env | grep MYSQL
  • Kontrollera containerprocesslistan:

    docker compose exec app ps aux
    
    docker compose exec app ss -ltnp
  • Kontrollera hälsan hos MySQL:

    docker compose exec db mysqladmin -u"${DB_USERNAME}" -p"${DB_PASSWORD}" ping

När man ska exponera värddatorns portar för felsökning

Som standard är db-tjänsten i denna konfiguration inte bunden till värdportar. Exponera portar endast för lokal felsökning. För att tillfälligt exponera MySQL på värden, lägg till följande under db i docker-compose.yml:

ports:
  - "3306:3306"

Starta sedan om:

docker compose up -d db

Efter debuggningsprocessen, ta bort ports-mappningen för att undvika att databasen exponeras mot nätverket.

Vanliga frågor

1. Behöver jag ha Composer installerat på värddatorn?

Nej. Du kan köra Composer helt och hållet inuti app-behållaren, vilket är det rekommenderade tillvägagångssättet för detta Compose-arbetsflöde. Dockerfile i handledningen inkluderar Composer, så kör kommandon som docker compose exec app composer install eller docker compose run --rm app composer require vendor/package. Att köra Composer i behållaren säkerställer att rätt PHP-version och tillägg används och undviker att skapa vendor-filer med felaktigt ägarskap på värddatorn.

2. Kan jag köra Laravel-migrationer från insidan av containern?

Ja. Kör migrationer från app-behållaren så att de använder samma körmiljö och nätverk som din applikation: docker compose exec app php artisan migrate. För engångs- eller CI-uppgifter kan du använda docker compose run --rm app php artisan migrate --force. Innan du kör migrationer, se till att databaskontainern är frisk och accepterar anslutningar, till exempel med docker compose exec db mysqladmin -u$ {DB_USERNAME} -p$ {DB_PASSWORD} ping eller genom att försöka igen tills den svarar.

3. Hur installerar jag ytterligare PHP-tillägg?

Lägg till nödvändiga systempaket och förlängningskommandon i Dockerfilen och bygg sedan om bilden. Till exempel, installera beroenden och bygg vanliga tillägg med något liknande:

RUN apt-get update && apt-get install -y libpng-dev libjpeg-dev \
  && docker-php-ext-configure gd --with-jpeg \
  && docker-php-ext-install pdo_mysql mbstring gd

Om du behöver ett PECL-tillägg, använd pecl install och docker-php-ext-enable. Efter att ha redigerat Dockerfile, kör docker compose build app och sedan docker compose up -d app för att tillämpa ändringarna.

4. Hur exponerar jag Nginx-containern för HTTPS?

Lägg till en HTTPS-serverblock i din Nginx-konfiguration, montera ditt certifikat och din nyckel i containern och publicera port 443 i docker-compose. Här är ett exempel med minimala ändringar i docker-compose.yml:

services:
  nginx:
    ports:
      - "8000:80"
      - "443:443"
    volumes:
      - ./docker-compose/nginx:/etc/nginx/conf.d
      - ./certs:/etc/nginx/certs:ro

Lägg sedan till ett SSL-serverblock som hänvisar till /etc/nginx/certs/fullchain.pem och /etc/nginx/certs/privkey.pem. För produktion, använd en omvänd proxy eller en certifikathanterare som Traefik eller en extern lastbalanserare för att skaffa och förnya certifikat på ett säkert sätt istället för att lagra privata nycklar i applikationsstacken.

5. Hur återuppbygger jag Laravel efter kodändringar?

Det beror på vad som ändrats. Om du använder bind mounts för projektkatalogen reflekteras ändringar i PHP, mallar, rutter och kontroller omedelbart; kör Laravel cache-återställningar vid behov, till exempel:

docker compose exec app php artisan config:clear

docker compose exec app php artisan route:clear

docker compose exec app php artisan view:clear

Om du ändrade Composer-beroenden eller Dockerfilen (nya tillägg eller systempaket), installera om eller bygg om: docker compose exec app composer install för ändringar i beroenden, och docker compose build app && docker compose up -d för ändringar i Dockerfilen. Starta om den påverkade tjänsten när du ändrar PHP-FPM- eller Nginx-konfigurationen: docker compose restart app eller docker compose restart nginx.

Slutsats

I den här guiden har vi satt upp en Docker-miljö med tre containrar och använder Docker Compose för att definiera vår infrastruktur i en YAML-fil.

Från och med nu kan du arbeta med din Laravel-applikation utan att behöva installera och ställa in en lokal webbserver för utveckling och testning. Dessutom kommer du att arbeta med en tillfällig miljö som enkelt kan replikeras och distribueras, vilket kan vara användbart både när du utvecklar din applikation och när du går mot en produktionsmiljö.

För fler Laravel-handledning, kolla in följande artiklar:

  • Hosta din Laravel-app på Linux-Console.net
  • Hur man installerar och konfigurerar Laravel med Nginx på Ubuntu (LEMP Stack)
  • Hur man skapar Laravel Eloquent API-resurser för att konvertera modeller till JSON
  • Hur man startar en ny Laravel-applikation med Docker Compose

Tack för att du lär dig tillsammans med Linux-Console.net-communityn.