Pengantar kontainer untuk aplikasi Java

Kontainer menyediakan lingkungan portabel yang konsisten untuk aplikasi Java Anda di seluruh tahap pengembangan, pengujian, dan produksi. Artikel ini memperkenalkan konsep kontainerisasi untuk aplikasi Java dan memandu Anda membuat, men-debug, mengoptimalkan, dan menyebarkan aplikasi Java dalam kontainer ke Azure Container Apps.

Dalam artikel ini, Anda mempelajari konsep kontainerisasi penting untuk pengembang Java dan keterampilan berikut:

  • Menyiapkan lingkungan pengembangan Anda untuk aplikasi Java dalam kontainer.
  • Membuat Dockerfiles yang dioptimalkan untuk beban kerja Java.
  • Mengonfigurasi alur kerja pengembangan lokal dengan kontainer.
  • Men-debug aplikasi Java dalam kontainer.
  • Mengoptimalkan kontainer Java untuk produksi.
  • Menyebarkan aplikasi Java kontainer Anda ke Azure Container Apps.

Dengan melakukan kontainerisasi aplikasi Java, Anda mendapatkan lingkungan yang konsisten, penyebaran yang disederhanakan, pemanfaatan sumber daya yang efisien, dan peningkatan skalabilitas.

Kontainer untuk aplikasi Java

Kontainer mengemas aplikasi dengan dependensinya, memastikan konsistensi di seluruh lingkungan. Untuk pengembang Java, ini berarti menggabungkan aplikasi, dependensinya, Java Runtime Environment/Java Development Kit (JRE/JDK), dan file konfigurasi ke dalam satu unit portabel.

Kontainerisasi memiliki keuntungan utama daripada virtualisasi yang membuatnya ideal untuk pengembangan cloud. Berbeda dengan komputer virtual, kontainer berjalan pada kernel OS host server. Ini bermanfaat untuk aplikasi Java, yang sudah berjalan di komputer virtual Java (JVM). Aplikasi Containerizing Java menambahkan overhead minimal dan memberikan manfaat penyebaran yang signifikan.

Ekosistem kontainer mencakup komponen utama berikut:

  • Gambar - cetak biru.
  • Kontainer - instansi yang berjalan.
  • Registri - tempat gambar disimpan.
  • Orkestrator - sistem yang mengelola kontainer dalam skala besar.

Docker adalah platform kontainerisasi paling populer, dan didukung dengan baik di ekosistem Azure melalui Azure Container Apps.

Menyiapkan lingkungan pengembangan Anda

Bagian ini memandu Anda menginstal alat yang diperlukan dan mengonfigurasi lingkungan pengembangan Anda untuk membangun, menjalankan, dan men-debug aplikasi Java dalam kontainer.

Menginstal alat yang diperlukan

Untuk membuat kontainer aplikasi Java, Anda memerlukan alat berikut yang diinstal pada komputer pengembangan Anda:

Verifikasi penginstalan Anda dengan menggunakan perintah berikut:

docker --version
docker compose version

Mengonfigurasi Visual Studio Code untuk pengembangan kontainer

Untuk pengembangan Java dalam kontainer, konfigurasikan Visual Studio Code dengan menginstal Java Extension Pack dan menyiapkan JDK Anda. Ekstensi Dev Containers memungkinkan Anda membuka folder apa pun di dalam kontainer dan menggunakan kumpulan fitur lengkap Visual Studio Code di dalam kontainer tersebut.

Untuk mengaktifkan Visual Studio Code membuat dan menyambungkan secara otomatis ke kontainer pengembangan, buat file .devcontainer/devcontainer.json di proyek Anda.

Misalnya, contoh konfigurasi berikut mendefinisikan build Java:

{
    "name": "Java Development",
    "image": "mcr.microsoft.com/devcontainers/java:21",
    "customizations": {
        "vscode": {
            "extensions": [
                "vscjava.vscode-java-pack",
                "ms-azuretools.vscode-docker"
            ]
        }
    },
    "forwardPorts": [8080, 5005],
    "remoteUser": "vscode"
}

Konfigurasi ini menggunakan gambar kontainer pengembangan Java Microsoft, menambahkan ekstensi penting, dan meneruskan port aplikasi, 8080, dan port debugging, 5005.

Membuat Dockerfile

Dockerfile berisi instruksi untuk membangun gambar Docker. Untuk aplikasi Java, Dockerfile biasanya menyertakan komponen berikut:

  • Gambar dasar dengan JDK atau JRE.
  • Instruksi untuk menyalin file aplikasi.
  • Perintah untuk mengatur variabel lingkungan.
  • Konfigurasi titik masuk.

Pilih gambar dasar

Memilih gambar dasar yang tepat sangat penting. Pertimbangkan opsi ini:

Deskripsi Nama Komentar
Gambar pengembangan Microsoft Java mcr.microsoft.com/java/jdk:21-zulu-ubuntu JDK penuh dan dioptimalkan untuk Azure
Gambar produksi Microsoft Java mcr.microsoft.com/java/jre:21-zulu-ubuntu Runtime saja dan dioptimalkan untuk Azure
Gambar pengembangan OpenJDK resmi openjdk:21-jdk JDK Penuh
Gambar produksi OpenJDK resmi openjdk:21-jre Hanya runtime

Untuk lingkungan pengembangan, gunakan gambar JDK lengkap. Untuk produksi, gunakan gambar JRE atau distroless untuk meminimalkan ukuran dan permukaan serangan aplikasi Anda.

Gambar Microsoft Java dilengkapi dengan pengoptimalan khusus Azure dan diperbarui secara teratur dengan patch keamanan, membuatnya ideal untuk aplikasi yang menargetkan Azure Container Apps.

Contoh Dockerfile Dasar

Contoh berikut menunjukkan Dockerfile sederhana untuk aplikasi Java:

FROM mcr.microsoft.com/java/jdk:21-zulu-ubuntu
WORKDIR /app
COPY target/myapp.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]

Untuk aplikasi Spring Boot, Anda dapat menyiapkan Dockerfile dengan basis berikut:

FROM mcr.microsoft.com/java/jdk:21-zulu-ubuntu
WORKDIR /app
COPY target/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-Dspring.profiles.active=docker", "-jar", "app.jar"]

Untuk penyebaran produksi, gunakan gambar JRE yang ditunjukkan dalam contoh berikut untuk mengurangi ukuran dan meminimalkan permukaan serangan aplikasi Anda:

FROM mcr.microsoft.com/java/jre:21-zulu-ubuntu
WORKDIR /app
COPY target/*.jar app.jar
EXPOSE 8080
ENV JAVA_OPTS="-Dserver.port=8080"
ENTRYPOINT ["java", ${JAVA_OPTS}, "-jar", "app.jar"]

Pengembangan lokal dengan kontainer

Kontainer dimaksudkan untuk dijalankan di berbagai konteks. Di bagian ini, Anda mempelajari alur pengembangan lokal untuk digunakan dengan kontainer.

Menggunakan Docker Compose untuk aplikasi multi-kontainer

Sebagian besar aplikasi Java berinteraksi dengan database, cache, atau layanan lainnya. Docker Compose membantu Anda menentukan dan mengatur aplikasi multi-kontainer menggunakan file konfigurasi YAML sederhana.

Apa itu Docker Compose?

Docker Compose adalah alat yang memungkinkan Anda melakukan tugas berikut:

  • Tentukan aplikasi multi-kontainer dalam satu file.
  • Kelola siklus hidup aplikasi, termasuk memulai, menghentikan, dan membangun kembali.
  • Pertahankan lingkungan terisolasi.
  • Membuat jaringan untuk komunikasi layanan.
  • Menyimpan data secara permanen menggunakan volume.

Contoh: Aplikasi Java dengan database

File compose.yml berikut mengonfigurasi aplikasi Java dengan database PostgreSQL:

version: '3.8'
services:
  app:
    build: .                              # Build from Dockerfile in current directory
    ports:
      - "8080:8080"                       # Map HTTP port
      - "5005:5005"                       # Map debug port
    environment:
      - SPRING_PROFILES_ACTIVE=dev
      - SPRING_DATASOURCE_URL=jdbc:postgresql://db:5432/myapp
    volumes:
      - ./target:/app/target              # Mount target directory for hot reloads
    depends_on:
      - db                                # Ensure database starts first
  
  db:
    image: postgres:13
    environment:
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=postgres
      - POSTGRES_DB=myapp
    ports:
      - "5432:5432"                       # Expose PostgreSQL port
    volumes:
      - postgres-data:/var/lib/postgresql/data  # Persist database data

volumes:
  postgres-data:                          # Named volume for database persistence

File ini memiliki karakteristik berikut:

  • Layanan dapat saling mereferensikan berdasarkan nama - misalnya, db di URL JDBC.
  • Docker Compose secara otomatis membuat jaringan untuk layanan.
  • Aplikasi Java menunggu database dimulai, karena depends_on.
  • Data database dipertahankan saat restart menggunakan volume bernama.

Perintah Umum Docker Compose

Setelah Anda membuat file compose.yml , kelola aplikasi Anda dengan menggunakan perintah berikut:

# Build images without starting containers
docker compose build

# Start all services defined in compose.yml
docker compose up

# Start in detached mode (run in background)
docker compose up -d

# View running containers managed by compose
docker compose ps

# View logs from all containers
docker compose logs

# View logs from a specific service
docker compose logs app

# Stop all services
docker compose down

# Stop and remove volumes (useful for database resets)
docker compose down -v

Alur kerja pengembangan

Alur kerja pengembangan Java umum menggunakan Docker Compose berisi langkah-langkah berikut:

  1. Buat file compose.yml dan Dockerfile.
  2. Jalankan docker compose up untuk memulai semua layanan.
  3. Buat perubahan pada kode Java Anda.
  4. Bangun kembali aplikasi Anda. Bergantung pada konfigurasi, Anda mungkin perlu menghidupkan ulang kontainer Anda.
  5. Uji perubahan di lingkungan kontainer.
  6. Setelah selesai, jalankan docker compose down.

Menjalankan kontainer tunggal dengan Docker

Untuk skenario yang lebih sederhana saat Anda tidak memerlukan beberapa layanan yang saling terhubung, Anda dapat menggunakan docker run perintah untuk memulai kontainer individual.

Perintah Docker berikut khas untuk aplikasi Java:

# Run a Java application JAR directly
docker run -p 8080:8080 myapp:latest

# Run with environment variables
docker run -p 8080:8080 -e "SPRING_PROFILES_ACTIVE=prod" myapp:latest

# Run in detached mode (background)
docker run -d -p 8080:8080 myapp:latest

# Run with a name for easy reference
docker run -d -p 8080:8080 --name my-java-app myapp:latest

# Run with volume mount for persistent data
docker run -p 8080:8080 -v ./data:/app/data myapp:latest

Men-debug aplikasi kontainer

Men-debug aplikasi Java dalam kontainer terkadang menantang karena kode Anda berjalan di lingkungan terisolasi di dalam kontainer.

Pendekatan debugging standar tidak selalu diterapkan secara langsung, tetapi dengan konfigurasi yang tepat, Anda dapat membuat koneksi debugging jarak jauh ke aplikasi Anda. Bagian ini menunjukkan kepada Anda cara mengonfigurasi kontainer untuk debugging, menyambungkan alat pengembangan Anda ke kontainer yang berjalan, dan memecahkan masalah umum terkait kontainer.

Menyiapkan debug jarak jauh

Men-debug aplikasi Java dalam kontainer memerlukan pengeksposan port debug dan mengonfigurasi IDE Anda untuk menyambungkannya. Anda dapat menyelesaikan tugas-tugas ini dengan menggunakan langkah-langkah berikut:

  1. Untuk mengaktifkan penelusuran kesalahan, ubah Dockerfile Anda sehingga berisi konten berikut:

    Nota

    Anda dapat mengubah perintah startup kontainer Anda, sebagai gantinya.

    FROM mcr.microsoft.com/java/jdk:21-zulu-ubuntu
    WORKDIR /app
    COPY target/*.jar app.jar
    EXPOSE 8080 5005
    ENTRYPOINT ["java", "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005", "-jar", "app.jar"]
    
  2. Konfigurasikan file launch.json Visual Studio Code untuk menyambungkan ke port debug, seperti yang ditunjukkan dalam contoh berikut:

    {
      "version": "0.2.0",
      "configurations": [
        {
          "type": "java",
          "name": "Debug in Container",
          "request": "attach",
          "hostName": "localhost",
          "port": 5005
        }
      ]
    }
    
  3. Mulai kontainer Anda dengan port 5005 yang dipetakan ke host Anda, lalu luncurkan debugger di Visual Studio Code.

Memecahkan masalah kontainer

Saat kontainer tidak berulah seperti yang diharapkan, Anda dapat memeriksa log aplikasi untuk menyelidiki masalah tersebut.

Gunakan perintah berikut untuk memecahkan masalah aplikasi Anda. Sebelum Anda menjalankan perintah ini, pastikan untuk mengganti placeholder (<...>) dengan nilai milik Anda.

# View logs
docker logs <CONTAINER_ID>

# Follow logs in real-time
docker logs -f <CONTAINER_ID>

# Inspect container details
docker inspect <CONTAINER_ID>

# Get a shell in the container
docker exec -it <CONTAINER_ID> bash

Untuk masalah khusus Java, aktifkan bendera JVM untuk diagnostik yang lebih baik, seperti yang ditunjukkan dalam contoh berikut:

ENTRYPOINT ["java", "-XX:+PrintFlagsFinal", "-XX:+PrintGCDetails", "-jar", "app.jar"]

Tabel berikut ini mencantumkan masalah umum dan solusi terkait:

Kesalahan Solusi yang mungkin
Kehabisan memori Meningkatkan batas memori kontainer
Waktu habis koneksi Periksa konfigurasi jaringan untuk adanya kesalahan. Lakukan pemeriksaan port dan aturan perutean.
Masalah izin Verifikasi izin sistem file.
Masalah classpath Periksa struktur dan dependensi JAR.

Mengoptimalkan kontainer Java

Aplikasi Java dalam kontainer memerlukan pertimbangan khusus untuk performa optimal. JVM dirancang sebelum teknologi kontainer umum. Menggunakan kontainer dapat menyebabkan masalah alokasi sumber daya jika tidak dikonfigurasi dengan benar.

Anda dapat secara signifikan meningkatkan performa dan efisiensi aplikasi Java kontainer Anda dengan menyempurnakan pengaturan memori, mengoptimalkan ukuran gambar, dan mengonfigurasi pengumpulan sampah. Bagian ini mencakup pengoptimalan penting untuk kontainer Java, dengan fokus pada manajemen memori, waktu startup, dan pemanfaatan sumber daya.

Konfigurasi memori JVM dalam kontainer

JVM tidak secara otomatis mendeteksi batas memori kontainer di Java 8. Untuk Java 9+, kesadaran kontainer diaktifkan secara default.

Konfigurasikan JVM Anda untuk mematuhi batas kontainer, seperti yang ditunjukkan dalam contoh berikut:

FROM mcr.microsoft.com/java/jre:21-zulu-ubuntu
WORKDIR /app
COPY target/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-XX:MaxRAMPercentage=75.0", "-jar", "app.jar"]

Bendera JVM berikut penting untuk aplikasi dalam kontainer:

  • -XX:MaxRAMPercentage=75.0. Mengatur timbunan maksimum sebagai persentase memori yang tersedia.
  • -XX:InitialRAMPercentage=50.0. Mengatur ukuran timbunan awal.
  • -Xmx dan -Xms. Bendera ini juga tersedia, tetapi memerlukan nilai tetap.

Bersiap untuk penerapan produksi

Memindahkan aplikasi Java dalam kontainer ke produksi memerlukan pertimbangan di luar fungsionalitas dasar.

Lingkungan produksi menuntut keamanan yang kuat, pemantauan yang andal, alokasi sumber daya yang tepat, dan fleksibilitas konfigurasi.

Bagian ini mencakup praktik dan konfigurasi penting yang diperlukan untuk menyiapkan kontainer Java Anda untuk penggunaan produksi. Bagian ini berfokus pada keamanan, pemeriksaan kesehatan, dan manajemen konfigurasi, untuk memastikan aplikasi Anda berjalan dengan andal dalam produksi.

Praktik terbaik keamanan

Amankan aplikasi Java kontainer Anda dengan menggunakan praktik berikut:

  • Konteks keamanan bawaan. Jalankan aplikasi Anda sebagai pengguna non-root, seperti yang ditunjukkan dalam contoh berikut:

    FROM mcr.microsoft.com/java/jre:21-zulu-ubuntu
    WORKDIR /app
    COPY target/*.jar app.jar
    RUN addgroup --system javauser && adduser --system --ingroup javauser javauser
    USER javauser
    ENTRYPOINT ["java", "-jar", "app.jar"]
    
  • Secara proaktif mengidentifikasi masalah. Pindai gambar kontainer secara teratur untuk kerentanan dengan menggunakan perintah berikut:

    docker scan myapp:latest
    
  • Kesegaran gambar dasar. Selalu perbarui gambar dasar Anda.

  • Manajemen rahasia. Menerapkan manajemen rahasia yang tepat. Misalnya, jangan mengodekan data sensitif secara permanen ke dalam aplikasi Anda, dan gunakan brankas kunci jika memungkinkan.

  • Konteks keamanan terbatas. Terapkan prinsip hak istimewa paling sedikit ke semua konteks keamanan.

  • Akses sistem file. Gunakan sistem berkas hanya baca jika memungkinkan.

Pemeriksaan dan pemantauan kesehatan

Periksa kesehatan aplikasi dengan pemeriksaan untuk memastikan aplikasi Anda berjalan dengan benar.

Untuk aplikasi Spring Boot, sertakan dependensi Aktuator untuk titik akhir kesehatan yang komprehensif, seperti yang ditunjukkan dalam contoh berikut:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

Konfigurasikan aplikasi Anda ke log output dalam format yang cocok untuk lingkungan kontainer, seperti JSON.

Menyebarkan ke Azure Container Apps

Bagian ini memandu Anda menyiapkan kontainer Java untuk penyebaran Azure Container Apps, dan menyoroti pertimbangan konfigurasi utama.

Menyiapkan kontainer Anda untuk Azure

  • Konfigurasi port. Pastikan kontainer Anda mendengarkan port yang disediakan oleh Azure, seperti yang ditunjukkan dalam contoh berikut:

    FROM mcr.microsoft.com/java/jre:21-zulu-ubuntu
    WORKDIR /app
    COPY target/*.jar app.jar
    ENV PORT=8080
    EXPOSE ${PORT}
    CMD java -jar app.jar --server.port=${PORT}
    
  • Pemeriksaan kesehatan. Terapkan pemeriksaan kesehatan untuk pemeriksaan keaktifan dan kesiapan Azure.

  • Konfigurasi log. Konfigurasikan pengelogan ke output ke stdout/stderr.

  • Rencanakan untuk hal yang tidak terduga. Siapkan proses penanganan penutupan sistem yang lancar dengan konfigurasi batas waktu. Untuk informasi selengkapnya, lihat Manajemen siklus hidup aplikasi di Azure Container Apps.