Heim  >  Artikel  >  Backend-Entwicklung  >  Dockerisierung einer Golang-API mit MySQL und Hinzufügen von Docker Compose-Unterstützung

Dockerisierung einer Golang-API mit MySQL und Hinzufügen von Docker Compose-Unterstützung

PHPz
PHPzOriginal
2024-09-04 16:39:08275Durchsuche

Das Entwickeln und Testen von APIs, die lokal mit einer Datenbank verbunden sind, ist kein Scherz. Die Datenbank wird oft zum Problempunkt. Mit Docker wird der Prozess jedoch einfacher und einfacher, was die Replikation vereinfacht. In diesem Blog werden wir sehen, wie wir eine Golang-API mit einer MySQL-Datenbank dockerisieren und sie auch Docker Compose-fähig machen können

Für die Demo habe ich diese RESTful Golang API erstellt. Wir können CRUD-Vorgänge wie das Erstellen, Löschen und Bearbeiten von Zeitplänen in der MySQL-Datenbank ausführen. Weitere Informationen zu den Endpunkten, Methoden usw. finden Sie in der README-Datei des Projekts. Wir werden nicht zu tief auf die Funktionsweise der API eingehen, da unser Hauptziel darin besteht, uns auf den Dockerisierungsteil zu konzentrieren.

Um eine App per Docker zu nutzen, müssen wir eine Docker-Datei erstellen. Lassen Sie mich Ihnen sagen, dass es Hunderte von Möglichkeiten gibt, eine Docker-Datei zu schreiben, und es gibt nichts falsch oder richtig, jede Einzelperson/jedes Unternehmen hat seine eigenen Praktiken und Schreibweisen. In unserem Fall werden wir vier der Best Practices in unserer Docker-Datei befolgen, um ein besseres und optimiertes Image zu erhalten, das kleiner und sicherer ist. Lassen Sie uns alle vier Praktiken verstehen und warum wir sie implementieren, bevor wir mit dem Schreiben einer Docker-Datei beginnen.

  • Verwendung leichterer Basisbilder: Für fast jede Sprache gibt es eine leichtere Version des Bildes. Mit „leichter“ meine ich nicht ein paar Megabyte kleiner, es kann 10x kleiner sein. Der Grund für „leichter“ ist, dass es keine unnötigen Abhängigkeiten enthält, was es kleiner und sicherer macht. Ja, mehr Abhängigkeiten bringen ein höheres Sicherheitsrisiko mit sich. Wir werden eine Bullseye- und eine Alpenversion für den Knoten, Golang usw. haben.

  • Mehrstufige Builds: Sie sind eine der Superkräfte von Docker. Sie ermöglichen es uns, die Build-Schritte parallel auszuführen und durch das Kopieren notwendiger Dateien und Dinge ein endgültiges Image zu erstellen von anderen Schritten und nur über Elemente verfügen, die zum Ausführen unseres Programms erforderlich sind.

  • Eine Binärdatei erstellen: Viele Sprachen unterstützen die Erstellung einer Binärdatei aus dem Quellcode, wodurch sie klein und viel einfacher auszuführen ist, da wir nicht mit dem vollständigen Quellcode umgehen müssen. Außerdem können wir in jeder Umgebung arbeiten, unabhängig von Sprachbarrieren.

  • Ebenen aufschlüsseln: Da wir wissen, dass jede Anweisung in einer Docker-Datei eine Ebene ist, ist die Aufteilung von Ebenen eine gute Möglichkeit, unseren Build schneller zu machen. Wenn wir beispielsweise alle Dateien (zusammen mit der zu installierenden Abhängigkeitsdatei) aus der Quelle kopieren und dann die Abhängigkeiten installieren, wird dies jedes Mal geschehen, wenn wir ein Image neu erstellen, selbst wenn wir keine Änderungen an den Abhängigkeiten vorgenommen haben Kopieren Sie alle Dateien und installieren Sie Abhängigkeiten. Um dies zu umgehen, unterteilen wir sie in mehrere Schichten und können die Abhängigkeitsdatei in einem Schritt kopieren und installieren. Und im nächsten Schritt können wir alle Dateien kopieren. Wenn wir nun eine Änderung am Code vornehmen und dieses Mal neu erstellen, wird nur die Ebene neu erstellt, in die wir alle Dateien kopieren, und der Abhängigkeitsschritt bleibt übrig (der zwischengespeichert wird, da keine Änderungen vorgenommen wurden). Ein Beispiel sehen wir auch in der folgenden Docker-Datei. Wir schreiben Dockerfile so, dass Dinge, die sich weniger ändern, wie Basis-Image, Abhängigkeiten usw., von oben nach unten erfolgen.

Hier ist also die Docker-Datei, die wir für unsere Go-API erstellt haben.

# Build Stage
FROM golang:alpine3.20 AS builder

WORKDIR /build

COPY go.mod go.sum ./
RUN go mod download

COPY . .
RUN go build -o /app .

# Final Stage
FROM alpine:3.20

COPY --from=builder /app /app
CMD ["/app"]

Im FROM können wir sehen, dass wir eine golang:alpine-Version als Basis-Image verwendet haben, anstatt ein vollständiges Golang-Image zu verwenden und den Steps Builder zu benennen. Der Name/die Bezeichnung hilft uns beim Kopieren der Dateien von einer Stufe zur anderen ein anderer. Danach haben wir ein Arbeitsverzeichnis erstellt. Anstatt dann alle Dateien zusammen zu kopieren, haben wir einfach die go.mod- und go.sum- und install-Abhängigkeiten kopiert (den Grund dafür habe ich oben im Punkt Ebenen aufschlüsseln erläutert).

Sobald die Abhängigkeiten installiert sind, kopieren wir die restlichen Dateien. Dann erstellen wir eine Binärdatei aus unserem Quellcode, indem wir „go build“ ausführen und die Binärdatei mit dem Ausgabeflag „-o“ an den aktuellen Speicherort benennen.

Jetzt wird es interessant: Im Endstadium brauchen wir kein Golang-Image oder ähnliches, wir können ein Alpine-Basis-Image verwenden, weil wir jetzt eine Binärdatei haben, und wir können auf jedem Linux-System laufen, unabhängig von der Programmierung sprachliche Besonderheiten. Im nächsten Schritt können wir die Binärdatei vom Builder-Schritt in die letzte Stufe kopieren und die Binärdatei ausführen.

Das ist es. Auf diese Weise können Dockerzie, unsere App und wir die Docker-Datei weiter verbessern, indem wir Best Practices wie das Erstellen eines Benutzers und die Ausführung als Nicht-Root-Benutzer usw. einführen. Jetzt können wir ein Image mit der Docker-Datei erstellen und ausführen und dann eine Verbindung zur Remote- oder Erstellen Sie einen lokalen MySQL-Server, indem Sie die erforderlichen Anmeldeinformationen bereitstellen und dann auf diese API-Endpunkte zugreifen.

But, we will not stop here we will take a step further, and we will also run a MySQL server in a container and connect with our app. But, one point to note here is we can run a spin of a MySQL container and connect our API container to that, but there is so much manual work and long commands to type in the terminal, and things can go wrong. To overcome this we will use Docker Compose instead to make our life easier.

Let's create a file called compose.yml and use the blow config.

services:
  app:
    container_name: go-api
    build:
      context: .
      dockerfile: Dockerfile
    image: go-api
    ports:
      - 8080:8080
    environment:
      - DB_HOST=mysql
      - DB_PORT=3306
      - DB_USER=user
      - DB_PASSWORD=password
      - DB_NAME=my-database
    depends_on:
      mysql:
        condition: service_healthy
    networks:
      - go-network

  mysql:
    container_name: go-mysql
    image: mysql:9.0
    environment:
      - MYSQL_ROOT_PASSWORD=password
      - MYSQL_USER=user
      - MYSQL_PASSWORD=password
    volumes:
      - dbdata:/var/lib/mysql
    networks:
      - go-network
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      interval: 10s
      timeout: 5s
      retries: 3

volumes:
  dbdata:

networks:
  go-network:
    driver: bridge

It's a pretty basic configuration, but a couple of key things I want to mention is that if we see DB_HOST is mysql, there is no localhost or ip because in compose services communicate with other services by the service name. This is out-of-the-box networking provided by Docker Compose.

Another point, it often happens when working with Docker Compose where we have two services: an app and a database, and the app service starts first and crashes because the database isn't ready when the app tries to connect. To overcome this, we set up a healthcheck for the database to confirm its readiness. Then, in our app service, we can use depends_on with a condition to ensure the app only starts when the database service is healthy.

Now when we do Docker compose for 1st time, we might encounter an error saying permission denied because it doesn't have permission as well as a database with the name my_database, so we need to both by execing into the container.

Dockerizing a Golang API with MySQL and adding Docker Compose Support

Even though our app has crashed the DB is still up and running. We can check by doing docker ps.

Dockerizing a Golang API with MySQL and adding Docker Compose Support

Now exec into the container by doing docker exec -it sh. Container ID can be copied from the output after executing docker ps. Once we exec into the container, now log into the mysql by the below command:

mysql -u root -p 

It will ask for the password, enter the password you mentioned in the compose.yml file. Once we log in, we can create a database. Create a database with the same name specified in the compose file. In my case, it's my_database. Execute the below command:

CREATE DATABASE my_database;

Now to give the right privileges and flush it execute the below command.

GRANT ALL PRIVILEGES ON my_database.* TO 'user'@'%';
FLUSH PRIVILEGES;

Once we are done, we need to stop the running compose service and restart again by doing docker compose up

Dockerizing a Golang API with MySQL and adding Docker Compose Support

That's it for this blog. I'm glad you're still reading and made it to the end—thank you so much for your support and reading. I sometimes share tips on Golang on Twitter. You can connect with me there.

Das obige ist der detaillierte Inhalt vonDockerisierung einer Golang-API mit MySQL und Hinzufügen von Docker Compose-Unterstützung. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn