Dies ist der Artikel zum 12. Tag von NewsPicks Adventskalender 2019. Gestern war @ nckens "Das neue Team hat Asana mit etwas Einfallsreichtum eingesetzt".
Dieses Mal werde ich verschiedene Dinge ausprobieren, indem ich den kürzlich zu GA gewordenen Cloud Run von GCP und Java-Anwendungen verwende, von denen zuvor gesagt wurde, dass sie nicht mit Containern kompatibel sind.
Ein Dienst, mit dem Sie zustandslose HTTP-Container in einer vollständig verwalteten Umgebung oder einem GKE-Cluster ausführen können. Es ähnelt Fargate in AWS, aber ich denke, es ist immer einfacher, HTTP-Container einzurichten und zu verwalten.
Ich denke, der größte Unterschied zwischen einer vollständig verwalteten Umgebung und GKE besteht darin, dass keine Fixkosten anfallen. Bei der Ausführung mit GKE fallen für die GCEs, aus denen der Cluster besteht, immer Kosten an. In einer vollständig verwalteten Umgebung wird Ihnen jedoch die Zeit in Rechnung gestellt, in der der Container betriebsbereit ist. Welches kostengünstiger ist, hängt von der Anwendung ab. Sie müssen es also selbst berechnen.
Andere Unterschiede bestehen darin, dass Sie den Maschinentyp ändern können, wenn Sie mit GKE arbeiten, und es gibt einige Unterschiede, z. B. ob Sie Zugriff auf die VPC haben oder nicht. Überprüfen Sie daher andere Einschränkungen als die Kosten und wählen Sie die optimale Umgebung aus.
Dieses Mal möchte ich die Kosten niedrig halten, ohne eine Verknüpfung mit anderen Diensten herzustellen. Daher werde ich Cloud Run in einer vollständig verwalteten Umgebung beschreiben.
In letzter Zeit denke ich, dass die Möglichkeiten, Anwendungen wie Mikrodienste und Serverless auszuführen, zunehmen. In diesen Umgebungen gibt es viele Fälle, in denen sich der Vorgang von der herkömmlichen Webanwendung unterscheidet, die immer ausgeführt wird, z. B. das Skalieren mithilfe eines Containers oder das vorübergehende Starten. Hier möchte ich kurz auf die Kompatibilität zwischen Java und Containern eingehen.
Bei der Verwendung der JVM denke ich, dass die Kompatibilität mit dem Container aus den folgenden Gründen nicht so gut ist.
Es gibt jedoch eine zunehmende Anzahl von Fällen, in denen der Server entsprechend der Auslastung automatisch skaliert wird, z. B. Mikrodienste und serverlos. In solchen Zeiten hat Java, das diese beiden Eigenschaften aufweist, im Vergleich zu anderen Sprachen große Nachteile.
Cloud Run, das Gegenstand dieses Artikels ist, ist auch eine serverlose Anwendung auf GKE oder in einer vollständig verwalteten Umgebung. Daher müssen diese Nachteile beseitigt werden, um JVM-Anwendungen in Cloud Run verarbeiten zu können. Hier kommt GraalVM ins Spiel.
GraalVM ist eine mehrsprachige Laufzeit, die Oracle 2018 angekündigt hat.
GraalVM kann beim Erstellen von Java verwendet werden, um durch AOT-Kompilierung ein sofort ausführbares natives Image zu erstellen.
Es ist wichtig zu beachten, dass GraalVM die JVM schneller startet und relativ weniger Ressourcen verbraucht, aber keineswegs schneller. In einigen Fällen ist es möglicherweise besser, die JVM zu verwenden. Sie müssen daher eine Auswahl treffen, je nachdem, wo Sie sie verwenden möchten. Dieses Mal werden wir GraalVM verwenden, um es für Container und Serverless zu optimieren.
Jetzt erstellen wir den Service. Um GraalVM zu verwenden, verwenden wir dieses Mal ein Framework namens Quarkus. Quarkus ist ein natives Kubernetes-Framework, das für GraalVM und HotSpot angepasst wurde und derzeit Java und Kotlin unterstützt. Die offizielle Version dieses Quarkus wurde ebenfalls am 25. November 2019 veröffentlicht. Daher gibt es immer noch einige Funktionen, die im Vergleich zu anderen Frameworks wie Spring nicht ausreichen, aber ich denke, dass Funktionen in Zukunft nach und nach hinzugefügt werden.
Zuerst erstellen wir eine Java-Anwendung, die ausgeführt werden soll. Der folgende Befehl erstellt ein Quarkus-Projekt.
mvn io.quarkus:quarkus-maven-plugin:1.0.1.Final:create \
-DprojectGroupId=org.acme \
-DprojectArtifactId=getting-started \
-DclassName="org.acme.quickstart.GreetingResource" \
-Dpath="/hello"
Als nächstes wird die Docker-Datei erstellt. Wenn Sie ein Projekt erstellen, werden automatisch eine Dokcer-Datei zum Ausführen von jvm und eine Docker-Datei zum Ausführen des nativen Images generiert. Wenn Sie diese Docker-Datei jedoch verwenden möchten, müssen Sie sie in der lokalen Umgebung erstellen. Erstellen Sie daher eine Docker-Datei, die beim Erstellen des Images des Containers erstellt wird. (Die diesmal erstellte wurde unter Bezugnahme auf die im offiziellen Quarkus-Dokument erstellt.)
Dockerfile.multistage
## Stage 1 : build with maven builder image with native capabilities
FROM quay.io/quarkus/centos-quarkus-maven:19.2.1 AS build
COPY ./ /usr/src/app
USER root
RUN chown -R quarkus /usr/src/app
USER quarkus
RUN mvn -f /usr/src/app/pom.xml -Pnative clean package
## Stage 2 : create the docker final image
FROM registry.access.redhat.com/ubi8/ubi-minimal
WORKDIR /work/
COPY --from=build /usr/src/app/target/*-runner /work/application
RUN chmod 775 /work
EXPOSE 8080
ENV DISABLE_SIGNAL_HANDLERS true
CMD ["./application", "-Dquarkus.http.host=0.0.0.0", "-Dquarkus.http.port=8080"]
Erstellen Sie dieses Image und führen Sie es aus, um die Anwendung zu starten.
CI/CD Als nächstes bereiten wir die CI / CD-Umgebung vor. Dieses Mal werde ich [Cloud Build] verwenden (https://cloud.google.com/cloud-build/docs/).
In Cloud Build wird jeder Build-Schritt in yml oder json beschrieben. Dieses Mal werde ich die folgenden Schritte beschreiben.
Die eigentliche yml-Datei sieht folgendermaßen aus:
cloudbuild.yml
steps:
- name: 'gcr.io/cloud-builders/docker'
id: 'Build Image'
args: ['build', '-t', 'asia.gcr.io/{MyProject}/quarkus-example', '.', '-f', './src/main/docker/Dockerfile.multistage']
dir: './'
- name: 'gcr.io/cloud-builders/docker'
id: 'Push to Container Registry'
args: ['push', 'asia.gcr.io/{MyProject}/quarkus-example']
dir: './'
- name: 'gcr.io/cloud-builders/docker'
id: 'Deploy to Cloud Run'
args: ['beta', 'run', 'deploy', 'quarkus-example', '--image', 'asia.gcr.io/{MyProject}/quarkus-example', '--platform', 'managed', '--region', 'asia-northeast1', '--allow-unauthenticated']
dir: './'
Die hier angezeigten gcr.io / cloud-builders / docker
und gcr.io / cloud-builders / docker
werden als Cloud-Builder bezeichnet und sind vorgefertigt, auf die Sie in den Erstellungsschritten für die Aufgabenausführung verweisen können. Es ist ein Bild. Diese werden von Cloud Build und anderen Communitys bereitgestellt.
Dieses Mal verwende ich die Docker- und Gcloud-Bilder, aber es gibt viele andere Bilder wie Kubectl und Gradle.
Legen Sie fest, dass der Cloud Build-Job ausgeführt wird, wenn im Master ein Commit ausgeführt wird. Wenn Sie den Auslöser betätigen, können Sie den Status jedes Schritts auf dem Bildschirm wie unten gezeigt anzeigen.
Wenn Sie versuchen, eine geeignete Funktion zu entwickeln und die Pull-Anforderung zusammenzuführen, wird der Build gestartet.
Ich werde die Antwortzeit des zuletzt erstellten Dienstes und den Betrieb der automatischen Skalierung überprüfen.
Dieses Mal werden wir Scalas Testtool Gatling verwenden. Mit Gatling werden die Testergebnisse als HTML ausgegeben, sodass Sie die Ergebnisse leicht erfassen können.
Obwohl es möglich ist, die folgenden Metriken in GCP zu erfassen, haben wir dieses Mal Gatling übernommen, weil wir auch Daten von der Client-Seite erfassen wollten.
Erstellen Sie zunächst ein leeres sbt-Projekt und fügen Sie die Bibliotheken zu plugins.sbt, build.sbt hinzu.
plugins.sbt
addSbtPlugin("io.gatling" % "gatling-sbt" % "3.1.0")
build.sbt
libraryDependencies += "io.gatling.highcharts" % "gatling-charts-highcharts" % "3.3.1" % "test,it"
libraryDependencies += "io.gatling" % "gatling-test-framework" % "3.3.1" % "test,it"
BasicSimulation.scala
package computerdatabase
import io.gatling.core.Predef._
import io.gatling.core.structure.ScenarioBuilder
import io.gatling.http.Predef._
import io.gatling.http.protocol.HttpProtocolBuilder
import scala.concurrent.duration._
class BasicSimulation extends Simulation {
val url = "your app url"
val httpProtocol: HttpProtocolBuilder = http
.baseUrl(url)
.acceptHeader("text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8")
.acceptEncodingHeader("gzip, deflate")
.acceptLanguageHeader("en-US,en;q=0.5")
.userAgentHeader("Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0")
val scn: ScenarioBuilder = scenario("cloud run example scinario")
.exec(http("cloud run example scinario")
.get("/"))
setUp(scn.inject(rampUsersPerSec(1) to (150) during (600 seconds)).protocols(httpProtocol))
}
Eine kurze Codebeschreibung besteht darin, die bereitgestellte Cloud Run-Anwendung über einen Zeitraum von 10 Minuten mit einer maximalen Last von 150 U / min schrittweise zu laden. Dieses Mal greifen wir nur auf einen Endpunkt zu, es ist jedoch möglich, mehrere Endpunkte zu laden. Testergebnis Lassen Sie uns nun das oben erstellte Szenario verschieben. Reaktionszeit Lassen Sie uns zunächst die Reaktionszeit überprüfen. Soweit ich aus diesem Balkendiagramm ersehen kann, haben die meisten Anfragen innerhalb von 800 ms eine Antwort erhalten.
Als nächstes überprüfen wir die automatische Skalierung. Die orange Linie steht für rps und das gestapelte Oberflächendiagramm für die Reaktionszeit. In diesem Zusammenhang gibt es einige Bereiche, in denen die Reaktionszeit langsam ist. Vielleicht liegt das an einem Kaltstart. Selbst wenn es kalt gestartet wird, werden die meisten Anforderungen innerhalb von 2 Sekunden zurückgegeben, sodass es möglicherweise möglich ist, dem Servicevorgang standzuhalten.
Wenn ich Cloud Run berühre, frage ich mich, ob es Situationen gibt, in denen mehrere Prozesse in einem Container gestartet werden müssen, weil keine Kommunikation zwischen Containern möglich ist oder weil keine Verbindung zu VPC hergestellt werden kann. Es gibt Einschränkungen, was getan werden kann, und es trifft die Wand. Überlegen. Es ist jedoch sehr einfach, eine Web-App zu starten. Wenn Sie also die Möglichkeit haben, können Sie sie zu einer Ihrer Optionen machen.
Eine letzte Anmerkung. Es besteht die Gefahr von Gebühren für die diesmal erstellten Elemente. Löschen Sie sie daher am Ende.
Morgen ist Tegoshi von NewsPicks, "Sign with Apple Story" von @ kohei1218. freue mich auf!
Recommended Posts