Continuous Integration und Continuous Delivery/Deployment (CI/CD) sind essentielle Praktiken in der modernen Softwareentwicklung. Für Angular-Anwendungen, insbesondere solche, die wie im vorherigen Kapitel beschrieben containerisiert wurden, bietet CI/CD erhebliche Vorteile:
In diesem Kapitel entwickeln wir eine umfassende CI/CD-Pipeline für unsere containerisierte Angular-Anwendung, die verschiedene Tools und Best Practices integriert.
Eine effektive CI/CD-Pipeline für Angular-Anwendungen sollte folgende Phasen umfassen:
Diese Phasen können je nach Umgebung (Development, Staging, Production) variieren oder zusammengefasst werden.
Eine gut definierte Branching-Strategie ist grundlegend für jeden CI/CD-Workflow. Für Angular-Projekte empfehlen wir folgende Struktur:
Diese Strategie, auch bekannt als GitFlow oder eine Variation davon, unterstützt parallele Entwicklung und stabile Releases.
Typischerweise werden für Angular-Anwendungen mindestens drei Umgebungen verwendet:
Für jede Umgebung sollten spezifische Konfigurationen und Zugriffsberechtigungen definiert werden.
GitLab CI ist eine leistungsstarke Lösung für CI/CD-Pipelines, die tief in GitLab integriert ist.
Erstellen Sie eine .gitlab-ci.yml-Datei im
Wurzelverzeichnis Ihres Projekts:
# Definieren der Stages für die Pipeline
stages:
- validate
- test
- build
- security
- publish
- deploy
- verify
# Globale Variablen für alle Jobs
variables:
DOCKER_REGISTRY: registry.gitlab.com
DOCKER_IMAGE: $CI_REGISTRY_IMAGE/angular-app
KUBERNETES_NAMESPACE: angular-apps
# Cache-Konfiguration für npm
cache:
key: ${CI_COMMIT_REF_SLUG}
paths:
- node_modules/
# Validierungsphase
lint:
stage: validate
image: node:20-alpine
script:
- npm ci
- npm run lint
- npm run format:check
# Testphase
unit-test:
stage: test
image: node:20-alpine
script:
- npm ci
- npm run test:ci
coverage: '/Statements\s+:\s+(\d+.?\d*)%/'
artifacts:
paths:
- coverage/
expire_in: 1 week
# Build-Phase
build-app:
stage: build
image: node:20-alpine
script:
- npm ci
- npm run build -- --configuration production
artifacts:
paths:
- dist/
expire_in: 1 day
# Sicherheitsüberprüfung
dependency-scan:
stage: security
image: node:20-alpine
script:
- npm ci
- npm audit --production
allow_failure: true
# Container-Image erstellen und in Registry pushen
build-image:
stage: publish
image: docker:20.10.16
services:
- docker:20.10.16-dind
variables:
DOCKER_TLS_CERTDIR: "/certs"
script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker build -t $DOCKER_IMAGE:$CI_COMMIT_SHA -t $DOCKER_IMAGE:latest .
- docker push $DOCKER_IMAGE:$CI_COMMIT_SHA
- docker push $DOCKER_IMAGE:latest
# Container-Sicherheitsscan
container-scan:
stage: security
image:
name: aquasec/trivy:latest
entrypoint: [""]
variables:
TRIVY_NO_PROGRESS: "true"
TRIVY_CACHE_DIR: .trivycache/
script:
- trivy image --exit-code 0 --severity HIGH,CRITICAL $DOCKER_IMAGE:$CI_COMMIT_SHA
cache:
paths:
- .trivycache/
allow_failure: true
# Development-Deployment
deploy-dev:
stage: deploy
image: alpine/helm:3.12.0
script:
- helm upgrade --install angular-dev ./angular-app
--set image.repository=$DOCKER_IMAGE
--set image.tag=$CI_COMMIT_SHA
--namespace $KUBERNETES_NAMESPACE-dev
environment:
name: development
url: https://dev.angular-app.example.com
only:
- develop
# Staging-Deployment
deploy-staging:
stage: deploy
image: alpine/helm:3.12.0
script:
- helm upgrade --install angular-staging ./angular-app
--set image.repository=$DOCKER_IMAGE
--set image.tag=$CI_COMMIT_SHA
--namespace $KUBERNETES_NAMESPACE-staging
environment:
name: staging
url: https://staging.angular-app.example.com
only:
- main
when: manual
# Production-Deployment
deploy-prod:
stage: deploy
image: alpine/helm:3.12.0
script:
- helm upgrade --install angular-prod ./angular-app
--set image.repository=$DOCKER_IMAGE
--set image.tag=$CI_COMMIT_SHA
--namespace $KUBERNETES_NAMESPACE-prod
environment:
name: production
url: https://angular-app.example.com
only:
- main
when: manual
# Smoke-Tests nach Deployment
smoke-test:
stage: verify
image: cypress/included:12.14.0
script:
- npm ci
- npm run cypress:run -- --config baseUrl=$CI_ENVIRONMENT_URL
only:
- develop
- mainFür eine sichere Konfiguration müssen verschiedene CI/CD-Variablen in GitLab definiert werden:
KUBERNETES_SERVER: Kubernetes API-Server-URLKUBERNETES_TOKEN: Zugriffstoken für den
Kubernetes-ClusterKUBERNETES_CERTIFICATE: CA-Zertifikat des
Kubernetes-ClustersDiese können in den CI/CD-Einstellungen des Projekts oder der Gruppe in GitLab konfiguriert werden.
GitHub Actions ist eine flexible CI/CD-Lösung direkt in GitHub integriert.
Erstellen Sie den Ordner .github/workflows und darin
eine Datei wie angular-cicd.yml:
name: Angular CI/CD Pipeline
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main, develop ]
env:
DOCKER_REGISTRY: ghcr.io
IMAGE_NAME: angular-app
HELM_CHART_PATH: ./angular-app
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Lint code
run: npm run lint
- name: Check formatting
run: npm run format:check
test:
needs: validate
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run unit tests
run: npm run test:ci
- name: Upload coverage report
uses: actions/upload-artifact@v3
with:
name: coverage-report
path: coverage/
build:
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Build Angular app
run: npm run build -- --configuration production
- name: Upload build artifacts
uses: actions/upload-artifact@v3
with:
name: angular-dist
path: dist/
security:
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run npm audit
run: npm audit --production
continue-on-error: true
- name: Run OWASP dependency check
uses: dependency-check/Dependency-Check_Action@main
with:
project: 'Angular App'
path: '.'
format: 'HTML'
out: 'reports'
- name: Upload security reports
uses: actions/upload-artifact@v3
with:
name: security-reports
path: reports/
publish:
needs: [build, security]
runs-on: ubuntu-latest
if: github.event_name == 'push'
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v4
- name: Download build artifacts
uses: actions/download-artifact@v3
with:
name: angular-dist
path: dist/
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.DOCKER_REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract Docker metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.DOCKER_REGISTRY }}/${{ github.repository_owner }}/${{ env.IMAGE_NAME }}
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
- name: Scan image for vulnerabilities
uses: aquasecurity/trivy-action@master
with:
image-ref: ${{ env.DOCKER_REGISTRY }}/${{ github.repository_owner }}/${{ env.IMAGE_NAME }}:${{ github.sha }}
format: 'sarif'
output: 'trivy-results.sarif'
severity: 'CRITICAL,HIGH'
- name: Upload Trivy scan results
uses: github/codeql-action/upload-sarif@v2
with:
sarif_file: 'trivy-results.sarif'
deploy-dev:
needs: publish
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/develop'
environment:
name: development
url: https://dev.angular-app.example.com
steps:
- uses: actions/checkout@v4
- name: Set up Helm
uses: azure/setup-helm@v3
- name: Set up Kubectl
uses: azure/setup-kubectl@v3
- name: Set up Kubernetes config
uses: azure/k8s-set-context@v3
with:
kubeconfig: ${{ secrets.KUBECONFIG }}
- name: Deploy to development
run: |
helm upgrade --install angular-dev ${{ env.HELM_CHART_PATH }} \
--set image.repository=${{ env.DOCKER_REGISTRY }}/${{ github.repository_owner }}/${{ env.IMAGE_NAME }} \
--set image.tag=${GITHUB_SHA::8} \
--set config.apiUrl=https://api-dev.example.com \
--namespace angular-apps-dev
- name: Run smoke tests
run: |
npm ci
npm run cypress:run -- --config baseUrl=https://dev.angular-app.example.com
deploy-prod:
needs: publish
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
environment:
name: production
url: https://angular-app.example.com
steps:
- uses: actions/checkout@v4
- name: Set up Helm
uses: azure/setup-helm@v3
- name: Set up Kubectl
uses: azure/setup-kubectl@v3
- name: Set up Kubernetes config
uses: azure/k8s-set-context@v3
with:
kubeconfig: ${{ secrets.KUBECONFIG }}
- name: Deploy to production
run: |
helm upgrade --install angular-prod ${{ env.HELM_CHART_PATH }} \
--set image.repository=${{ env.DOCKER_REGISTRY }}/${{ github.repository_owner }}/${{ env.IMAGE_NAME }} \
--set image.tag=${GITHUB_SHA::8} \
--set config.apiUrl=https://api.example.com \
--namespace angular-apps-prod
- name: Run smoke tests
run: |
npm ci
npm run cypress:run -- --config baseUrl=https://angular-app.example.comGitHub Actions benötigt verschiedene Secrets für sichere Deployments:
KUBECONFIG: Kubernetes-Konfiguration für
Cluster-ZugriffDiese können in den Repository- oder Umgebungseinstellungen definiert werden.
Azure DevOps bietet eine umfassende Lösung für CI/CD-Pipelines, insbesondere für Teams, die bereits auf Microsoft-Technologien setzen.
Erstellen Sie eine Datei azure-pipelines.yml im
Wurzelverzeichnis des Projekts:
trigger:
branches:
include:
- main
- develop
- release/*
pool:
vmImage: 'ubuntu-latest'
variables:
- group: angular-app-variables
- name: dockerRegistry
value: 'yourregistry.azurecr.io'
- name: imageName
value: 'angular-app'
- name: helmChartPath
value: './angular-app'
stages:
- stage: Build
jobs:
- job: BuildAndTest
steps:
- task: NodeTool@0
inputs:
versionSpec: '20.x'
displayName: 'Install Node.js'
- script: |
npm ci
displayName: 'Install dependencies'
- script: |
npm run lint
displayName: 'Lint code'
- script: |
npm run test:ci
displayName: 'Run unit tests'
- task: PublishTestResults@2
inputs:
testResultsFormat: 'JUnit'
testResultsFiles: '**/junit.xml'
mergeTestResults: true
displayName: 'Publish test results'
- task: PublishCodeCoverageResults@1
inputs:
codeCoverageTool: 'Cobertura'
summaryFileLocation: '$(System.DefaultWorkingDirectory)/coverage/cobertura-coverage.xml'
displayName: 'Publish code coverage'
- script: |
npm run build -- --configuration production
displayName: 'Build Angular app'
- task: Docker@2
inputs:
containerRegistry: 'AzureContainerRegistry'
repository: '$(imageName)'
command: 'buildAndPush'
Dockerfile: 'Dockerfile'
tags: |
$(Build.BuildId)
latest
displayName: 'Build and push Docker image'
- task: AzureKeyVault@2
inputs:
azureSubscription: 'Your-Azure-Subscription'
KeyVaultName: 'your-keyvault'
SecretsFilter: '*'
displayName: 'Get KeyVault secrets'
- task: HelmDeploy@0
inputs:
connectionType: 'Azure Resource Manager'
azureSubscription: 'Your-Azure-Subscription'
azureResourceGroup: 'AKS-ResourceGroup'
kubernetesCluster: 'Your-AKS-Cluster'
command: 'package'
chartPath: '$(helmChartPath)'
destination: '$(Build.ArtifactStagingDirectory)'
displayName: 'Package Helm chart'
- task: PublishBuildArtifacts@1
inputs:
PathtoPublish: '$(Build.ArtifactStagingDirectory)'
ArtifactName: 'helm-chart'
publishLocation: 'Container'
displayName: 'Publish Helm chart artifact'
- stage: DeployDev
dependsOn: Build
condition: succeeded()
jobs:
- deployment: DeployToDev
environment: development
strategy:
runOnce:
deploy:
steps:
- task: HelmDeploy@0
inputs:
connectionType: 'Azure Resource Manager'
azureSubscription: 'Your-Azure-Subscription'
azureResourceGroup: 'AKS-ResourceGroup'
kubernetesCluster: 'Your-AKS-Cluster'
namespace: 'angular-apps-dev'
command: 'upgrade'
chartType: 'FilePath'
chartPath: '$(Pipeline.Workspace)/helm-chart/angular-app-*.tgz'
releaseName: 'angular-dev'
overrideValues: 'image.repository=$(dockerRegistry)/$(imageName),image.tag=$(Build.BuildId),config.apiUrl=https://api-dev.example.com'
displayName: 'Deploy to Dev with Helm'
- stage: DeployProd
dependsOn: DeployDev
condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/main'))
jobs:
- deployment: DeployToProd
environment: production
strategy:
runOnce:
deploy:
steps:
- task: HelmDeploy@0
inputs:
connectionType: 'Azure Resource Manager'
azureSubscription: 'Your-Azure-Subscription'
azureResourceGroup: 'AKS-ResourceGroup'
kubernetesCluster: 'Your-AKS-Cluster'
namespace: 'angular-apps-prod'
command: 'upgrade'
chartType: 'FilePath'
chartPath: '$(Pipeline.Workspace)/helm-chart/angular-app-*.tgz'
releaseName: 'angular-prod'
overrideValues: 'image.repository=$(dockerRegistry)/$(imageName),image.tag=$(Build.BuildId),config.apiUrl=https://api.example.com'
displayName: 'Deploy to Prod with Helm'In Azure DevOps können Sie Variablengruppen und Umgebungen definieren, um Konfigurationen und Sicherheitsrichtlinien zu verwalten:
angular-app-variables mit gemeinsamen
KonfigurationenFür Teams, die bereits Jenkins nutzen, ist die Integration einer Angular-CI/CD-Pipeline möglich.
Erstellen Sie eine Jenkinsfile im Wurzelverzeichnis:
pipeline {
agent {
kubernetes {
yaml """
apiVersion: v1
kind: Pod
spec:
containers:
- name: node
image: node:20-alpine
command:
- cat
tty: true
- name: docker
image: docker:20.10.16-dind
command:
- cat
tty: true
volumeMounts:
- mountPath: /var/run/docker.sock
name: docker-sock
- name: helm
image: alpine/helm:3.12.0
command:
- cat
tty: true
volumes:
- name: docker-sock
hostPath:
path: /var/run/docker.sock
"""
}
}
environment {
DOCKER_REGISTRY = 'your-registry.example.com'
IMAGE_NAME = 'angular-app'
HELM_CHART_PATH = './angular-app'
}
stages {
stage('Checkout') {
steps {
checkout scm
}
}
stage('Install Dependencies') {
steps {
container('node') {
sh 'npm ci'
}
}
}
stage('Lint') {
steps {
container('node') {
sh 'npm run lint'
}
}
}
stage('Test') {
steps {
container('node') {
sh 'npm run test:ci'
}
}
post {
always {
junit 'junit.xml'
publishHTML(target: [
allowMissing: false,
alwaysLinkToLastBuild: false,
keepAll: true,
reportDir: 'coverage',
reportFiles: 'index.html',
reportName: 'Coverage Report'
])
}
}
}
stage('Build') {
steps {
container('node') {
sh 'npm run build -- --configuration production'
}
}
}
stage('Build and Push Docker Image') {
steps {
container('docker') {
withCredentials([usernamePassword(credentialsId: 'docker-registry-credentials', usernameVariable: 'DOCKER_USERNAME', passwordVariable: 'DOCKER_PASSWORD')]) {
sh '''
docker login -u $DOCKER_USERNAME -p $DOCKER_PASSWORD $DOCKER_REGISTRY
docker build -t $DOCKER_REGISTRY/$IMAGE_NAME:$BUILD_NUMBER -t $DOCKER_REGISTRY/$IMAGE_NAME:latest .
docker push $DOCKER_REGISTRY/$IMAGE_NAME:$BUILD_NUMBER
docker push $DOCKER_REGISTRY/$IMAGE_NAME:latest
'''
}
}
}
}
stage('Deploy to Development') {
when {
branch 'develop'
}
steps {
container('helm') {
withCredentials([file(credentialsId: 'kubeconfig', variable: 'KUBECONFIG')]) {
sh '''
helm upgrade --install angular-dev $HELM_CHART_PATH \
--set image.repository=$DOCKER_REGISTRY/$IMAGE_NAME \
--set image.tag=$BUILD_NUMBER \
--set config.apiUrl=https://api-dev.example.com \
--namespace angular-apps-dev \
--kubeconfig $KUBECONFIG
'''
}
}
}
}
stage('Deploy to Production') {
when {
branch 'main'
}
steps {
timeout(time: 1, unit: 'DAYS') {
input message: 'Deploy to Production?', ok: 'Yes'
}
container('helm') {
withCredentials([file(credentialsId: 'kubeconfig', variable: 'KUBECONFIG')]) {
sh '''
helm upgrade --install angular-prod $HELM_CHART_PATH \
--set image.repository=$DOCKER_REGISTRY/$IMAGE_NAME \
--set image.tag=$BUILD_NUMBER \
--set config.apiUrl=https://api.example.com \
--namespace angular-apps-prod \
--kubeconfig $KUBECONFIG
'''
}
}
}
}
}
post {
always {
cleanWs()
}
success {
echo 'Pipeline completed successfully!'
}
failure {
echo 'Pipeline failed!'
}
}
}Für Jenkins benötigen Sie verschiedene Credentials und Plugins:
Angular verwendet Karma und Jasmine für Unit-Tests. Für CI/CD-Pipelines benötigen wir eine Headless-Browser-Konfiguration:
// karma.conf.ci.js
module.exports = function(config) {
config.set({
basePath: '',
frameworks: ['jasmine', '@angular-devkit/build-angular'],
plugins: [
require('karma-jasmine'),
require('karma-chrome-launcher'),
require('karma-jasmine-html-reporter'),
require('karma-coverage'),
require('karma-junit-reporter'),
require('@angular-devkit/build-angular/plugins/karma')
],
client: {
clearContext: false
},
coverageReporter: {
dir: require('path').join(__dirname, './coverage'),
subdir: '.',
reporters: [
{ type: 'html' },
{ type: 'text-summary' },
{ type: 'cobertura' }
]
},
reporters: ['progress', 'kjhtml', 'coverage', 'junit'],
junitReporter: {
outputDir: './junit',
outputFile: 'junit.xml',
useBrowserName: false
},
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: false,
browsers: ['ChromeHeadlessCI'],
customLaunchers: {
ChromeHeadlessCI: {
base: 'ChromeHeadless',
flags: ['--no-sandbox']
}
},
singleRun: true
});
};Fügen Sie ein entsprechendes NPM-Skript hinzu:
{
"scripts": {
"test:ci": "ng test --karma-config=karma.conf.ci.js --code-coverage --watch=false"
}
}Cypress ist eine der besten Optionen für E2E-Tests bei Angular-Anwendungen:
// cypress.config.ts
import { defineConfig } from 'cypress';
export default defineConfig({
e2e: {
baseUrl: 'http://localhost:4200',
supportFile: 'cypress/support/e2e.ts',
specPattern: 'cypress/e2e/**/*.cy.ts',
video: true,
screenshotOnRunFailure: true,
reporter: 'junit',
reporterOptions: {
mochaFile: 'cypress/results/results-[hash].xml',
toConsole: true
}
}
});Mit dem entsprechenden NPM-Skript:
{
"scripts": {
"cypress:run": "cypress run"
}
}Stellen Sie sicher, dass Ihre Pipelines Testabdeckungsberichte generieren und Qualitätsmetriken aufzeichnen. Diese Berichte sollten die folgenden Aspekte abdecken:
Tools wie SonarQube, Codacy oder CodeClimate können in Ihre Pipeline integriert werden, um diese Metriken zu verfolgen und zu visualisieren.
Angular bietet integrierte Möglichkeiten zur Verwaltung verschiedener Umgebungskonfigurationen.
Verwenden Sie die Umgebungsdateien in Angular, um umgebungsspezifische Konfigurationen zu verwalten:
// environment.ts (Development)
export const environment = {
production: false,
apiUrl: 'http://localhost:3000/api',
enableDebug: true
};
// environment.prod.ts (Production)
export const environment = {
production: true,
apiUrl: 'https://api.example.com',
enableDebug: false
};
// environment.staging.ts (Staging)
export const environment = {
production: false,
apiUrl: 'https://api-staging.example.com',
enableDebug: false
};Ergänzen Sie die angular.json-Datei, um verschiedene
Build-Konfigurationen zu unterstützen:
{
"projects": {
"your-app": {
"architect": {
"build": {
"configurations": {
"production": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
}
],
"optimization": true,
"outputHashing": "all",
"sourceMap": false,
"namedChunks": false,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": true,
"budgets": [
{
"type": "initial",
"maximumWarning": "2mb",
"maximumError": "5mb"
}
]
},
"staging": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.staging.ts"
}
],
"optimization": true,
"outputHashing": "all",
"sourceMap": true,
"namedChunks": false,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": true
}
}
}
}
}
}
}Für containerisierte Anwendungen kann es sinnvoll sein, bestimmte Konfigurationen zur Laufzeit zu injizieren:
FROM nginx:alpine
# Kopieren der statischen Dateien
COPY dist/your-app /usr/share/nginx/html
# Kopieren des Nginx-Konfigurationstemplate
COPY nginx.conf /etc/nginx/conf.d/default.conf
# Kopieren eines Startup-Skripts
COPY startup.sh /usr/share/nginx/
# Umgebungsvariablen festlegen
ENV API_URL=https://api.example.com
ENV AUTH_URL=https://auth.example.com
# Container-Startbefehl
CMD ["/bin/sh", "/usr/share/nginx/startup.sh"]Mit einem entsprechenden Startup-Skript startup.sh:
#!/bin/sh
# Ersetzen von Platzhaltern in der index.html mit Umgebungsvariablen
sed -i "s|__API_URL__|$API_URL|g" /usr/share/nginx/html/main*.js
sed -i "s|__AUTH_URL__|$AUTH_URL|g" /usr/share/nginx/html/main*.js
# Starten von Nginx im Vordergrund
nginx -g "daemon off;"Eine effektive CI/CD-Pipeline sollte Monitoring und Fehlerbehandlung integrieren, um Probleme schnell zu erkennen und zu beheben.
Implementieren Sie Monitoring-Tools wie:
Konfigurieren Sie ein zentrales Logging-System für Ihre Angular-Anwendung:
// logger.service.ts
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { environment } from '../environments/environment';
export enum LogLevel {
Info = 'info',
Warning = 'warning',
Error = 'error'
}
@Injectable({
providedIn: 'root'
})
export class LoggerService {
constructor(private http: HttpClient) {}
log(level: LogLevel, message: string, context?: any): void {
// Für Entwicklungsumgebungen
if (!environment.production) {
console.log(`[${level.toUpperCase()}]`, message, context || '');
}
// Für Produktionsumgebungen zu einem Log-Server senden
if (environment.logServerUrl) {
this.http.post(environment.logServerUrl, {
level,
message,
context,
timestamp: new Date().toISOString(),
userAgent: navigator.userAgent,
url: window.location.href
}).subscribe();
}
}
info(message: string, context?: any): void {
this.log(LogLevel.Info, message, context);
}
warning(message: string, context?: any): void {
this.log(LogLevel.Warning, message, context);
}
error(message: string, context?: any): void {
this.log(LogLevel.Error, message, context);
}
}Richten Sie Benachrichtigungen für CI/CD-Fehler und Anwendungsprobleme ein:
Eine CI/CD-Pipeline sollte kontinuierlich verbessert werden, um die Effizienz und Effektivität zu steigern.
Erfassen Sie Metriken über Ihre CI/CD-Pipeline:
Basierend auf den gesammelten Metriken können Sie verschiedene Optimierungen vornehmen:
# Beispiel für Test-Parallelisierung in GitHub Actions
test:
runs-on: ubuntu-latest
strategy:
matrix:
shard: [1, 2, 3, 4]
steps:
- uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install dependencies
run: npm ci
- name: Run tests (shard ${{ matrix.shard }})
run: npm run test:ci -- --shard=${{ matrix.shard }}/4Eine effektive CI/CD-Pipeline für Angular-Anwendungen bietet erhebliche Vorteile für die Softwarequalität und die Entwicklungsgeschwindigkeit. Die in diesem Kapitel vorgestellten Praktiken und Konfigurationen bilden eine solide Grundlage für die Implementierung von CI/CD in Ihrem Projekt.
Bewerten Sie Ihre Pipeline anhand der folgenden Kriterien:
Basierend auf der aktuellen Pipeline können die folgenden Erweiterungen in Betracht gezogen werden:
Mit diesen fortgeschrittenen Praktiken können Sie Ihre CI/CD-Pipeline weiter verbessern und die Qualität und Zuverlässigkeit Ihrer Angular-Anwendungen steigern.