DevOpsエンジニア完全ロードマップ

DevOpsKubernetesTerraformCI/CDクラウドインフラストラクチャ自動化

技術

DevOpsエンジニア完全ロードマップ

概要

DevOpsエンジニアは、開発と運用の橋渡しとなり、自動化、効率化、そして信頼性の高いソフトウェアデリバリーを実現する専門家です。2025年において、DevOpsはプラットフォームエンジニアリングへと進化し、開発者が高速に価値を提供できる再利用可能なセルフサービスインフラストラクチャを構築することが中心となっています。GitOps、AI駆動の自動化、そしてクラウドネイティブ技術が主流となっています。

詳細

フェーズ1: 基礎固め(3-6ヶ月)

Linux基礎とシステム管理

  • Linuxマスタリー

    • シェルスクリプティング(Bash、Zsh)
    • ファイルシステムとパーミッション
    • プロセス管理とシステムリソース
    • ネットワーク基礎(TCP/IP、DNS、HTTP/HTTPS)
    • systemdとサービス管理
  • 基本的なツール

    • テキスト処理(grep、sed、awk)
    • システム監視(top、htop、iostat、netstat)
    • パッケージ管理(apt、yum、dnf)
    • SSH設定とセキュリティ

プログラミングスキル

  • スクリプティング言語

    • Python(自動化スクリプト)
    • Go(ツール開発)
    • JavaScript(Node.js環境)
  • バージョン管理

    • Git完全理解(ブランチ戦略、マージ、リベース)
    • GitLab/GitHub/Bitbucket
    • コードレビューのベストプラクティス

クラウド基礎

  • 主要クラウドプラットフォーム
    • AWS(EC2、S3、IAM、VPC)
    • Google Cloud Platform(Compute Engine、Cloud Storage)
    • Azure(Virtual Machines、Storage Accounts)

フェーズ2: コンテナとオーケストレーション(6-12ヶ月)

Docker完全習得

  • コンテナ基礎

    • Dockerfileの最適化
    • マルチステージビルド
    • イメージレイヤーの理解
    • セキュリティスキャン(Trivy、Snyk)
  • 実践的なDocker

    • Docker Compose
    • ボリュームとネットワーク
    • レジストリ管理(Docker Hub、Harbor)
    • イメージサイズの最小化(distroless、Alpine)

Kubernetes習得

  • コア概念

    • アーキテクチャ(Control Plane、Worker Nodes)
    • 基本リソース(Pod、Service、Deployment、StatefulSet)
    • ストレージ(PV、PVC、StorageClass)
    • ネットワーキング(Service、Ingress、NetworkPolicy)
  • 高度な機能

    • ConfigMapとSecrets管理
    • RBAC(Role-Based Access Control)
    • Helm Charts
    • オートスケーリング(HPA、VPA、Cluster Autoscaler)
    • Service Mesh(Istio、Linkerd)

Infrastructure as Code

  • Terraform

    • HCL構文
    • モジュール開発
    • 状態管理とリモートバックエンド
    • Terraformワークスペース
    • プロバイダー開発
  • その他のIaCツール

    • Ansible(構成管理)
    • Pulumi(プログラマブルIaC)
    • CloudFormation(AWS専用)

フェーズ3: CI/CDとGitOps(12-18ヶ月)

CI/CDパイプライン

  • GitHub Actions

    • ワークフロー構築
    • カスタムアクション開発
    • マトリックスビルド
    • セキュリティスキャン統合
    • デプロイメント自動化
  • その他のCI/CDツール

    • Jenkins(パイプラインas Code)
    • GitLab CI/CD
    • CircleCI
    • ArgoCD(GitOps)

GitOps実践

  • GitOpsの原則

    • 宣言的設定
    • Gitを信頼できる唯一の情報源として使用
    • 自動化されたデプロイメント
    • 継続的な同期
  • 実装パターン

    • ArgoCD/Flux
    • Kustomize
    • Progressive Delivery(Flagger)
    • ロールバック戦略

モニタリングとオブザーバビリティ

  • メトリクス収集

    • Prometheus
    • Grafana
    • アラート設定(Alertmanager)
  • ログ管理

    • ELK Stack(Elasticsearch、Logstash、Kibana)
    • Fluentd/Fluent Bit
    • Loki
  • 分散トレーシング

    • Jaeger
    • Zipkin
    • OpenTelemetry

フェーズ4: 高度なDevOpsとプラットフォームエンジニアリング(18-24ヶ月)

セキュリティ(DevSecOps)

  • コンテナセキュリティ

    • イメージスキャン
    • ランタイムセキュリティ(Falco)
    • Pod Security Standards
    • OPA(Open Policy Agent)
  • シークレット管理

    • HashiCorp Vault
    • Kubernetes Secrets
    • External Secrets Operator
    • SOPS
  • コンプライアンス自動化

    • CIS Benchmarks
    • STIG compliance
    • 監査ログ

AI駆動の自動化

  • AIとMLOps統合

    • 自己修復インフラストラクチャ
    • 予測的スケーリング
    • 異常検知
    • インテリジェントアラート
  • ChatOpsとAI

    • Slackボット自動化
    • インシデント対応の自動化
    • AI支援のトラブルシューティング

プラットフォームエンジニアリング

  • 開発者エクスペリエンス

    • セルフサービスポータル
    • 内部開発者プラットフォーム(IDP)
    • ゴールデンパス提供
    • 開発環境の標準化
  • Platform as a Service構築

    • Backstage(開発者ポータル)
    • Crossplane(クラウドリソース管理)
    • サービスカタログ
    • コスト管理と最適化

SRE(Site Reliability Engineering)

  • 信頼性の原則

    • SLI/SLO/SLA定義
    • エラーバジェット
    • トイルの削減
    • ポストモーテム文化
  • カオスエンジニアリング

    • Chaos Monkey
    • Litmus
    • 障害注入テスト
    • 復旧手順の自動化

メリット・デメリット

メリット

  • 高い需要: DevOpsスキルは2025年も最も求められるスキルセットの一つ
  • 幅広いスキル: インフラ、開発、セキュリティ全般の知識が身につく
  • 自動化の達成感: 手作業を自動化し、効率を大幅に向上できる
  • キャリアの柔軟性: SRE、プラットフォームエンジニア、クラウドアーキテクトへの道
  • イノベーションの最前線: 最新技術を常に扱える環境

デメリット

  • 学習範囲の広さ: 多岐にわたる技術スタックの習得が必要
  • 常時待機の可能性: 24/7のシステム運用で緊急対応が必要
  • 変化の速さ: ツールや技術の更新速度が非常に速い
  • 責任の重さ: インフラ障害は全体に影響を与える
  • ストレス: 複数チーム間の調整とコミュニケーション

参考ページ

書き方の例

GitHub ActionsによるCI/CDパイプライン

# .github/workflows/deploy.yml
name: Build and Deploy to Kubernetes

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

env:
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}

jobs:
  build-and-test:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write
      
    steps:
    - name: Checkout code
      uses: actions/checkout@v3

    - name: Set up Docker Buildx
      uses: docker/setup-buildx-action@v2

    - name: Log in to GitHub Container Registry
      uses: docker/login-action@v2
      with:
        registry: ${{ env.REGISTRY }}
        username: ${{ github.actor }}
        password: ${{ secrets.GITHUB_TOKEN }}

    - name: Extract metadata
      id: meta
      uses: docker/metadata-action@v4
      with:
        images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
        tags: |
          type=ref,event=branch
          type=ref,event=pr
          type=semver,pattern={{version}}
          type=semver,pattern={{major}}.{{minor}}
          type=sha

    - name: Build and push Docker image
      uses: docker/build-push-action@v4
      with:
        context: .
        push: true
        tags: ${{ steps.meta.outputs.tags }}
        labels: ${{ steps.meta.outputs.labels }}
        cache-from: type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:buildcache
        cache-to: type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:buildcache,mode=max

    - name: Run Trivy vulnerability scanner
      uses: aquasecurity/trivy-action@master
      with:
        image-ref: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.meta.outputs.version }}
        format: 'sarif'
        output: 'trivy-results.sarif'

    - name: Upload Trivy scan results to GitHub Security
      uses: github/codeql-action/upload-sarif@v2
      with:
        sarif_file: 'trivy-results.sarif'

  deploy:
    needs: build-and-test
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
    
    steps:
    - name: Checkout code
      uses: actions/checkout@v3

    - name: Install kubectl
      uses: azure/setup-kubectl@v3
      with:
        version: 'v1.28.0'

    - name: Configure AWS credentials
      uses: aws-actions/configure-aws-credentials@v2
      with:
        aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
        aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
        aws-region: ap-northeast-1

    - name: Update kubeconfig
      run: |
        aws eks update-kubeconfig --name production-cluster --region ap-northeast-1

    - name: Deploy to Kubernetes
      run: |
        kubectl set image deployment/app app=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:sha-${GITHUB_SHA::7} -n production
        kubectl rollout status deployment/app -n production

Terraform によるインフラストラクチャ構築

# main.tf - EKSクラスター構築
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
    kubernetes = {
      source  = "hashicorp/kubernetes"
      version = "~> 2.23"
    }
  }

  backend "s3" {
    bucket = "terraform-state-bucket"
    key    = "eks/terraform.tfstate"
    region = "ap-northeast-1"
  }
}

# VPCモジュール
module "vpc" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "5.0.0"

  name = "${var.cluster_name}-vpc"
  cidr = "10.0.0.0/16"

  azs             = data.aws_availability_zones.available.names
  private_subnets = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
  public_subnets  = ["10.0.101.0/24", "10.0.102.0/24", "10.0.103.0/24"]

  enable_nat_gateway   = true
  single_nat_gateway   = false
  enable_dns_hostnames = true

  tags = {
    "kubernetes.io/cluster/${var.cluster_name}" = "shared"
  }

  public_subnet_tags = {
    "kubernetes.io/cluster/${var.cluster_name}" = "shared"
    "kubernetes.io/role/elb"                    = "1"
  }

  private_subnet_tags = {
    "kubernetes.io/cluster/${var.cluster_name}" = "shared"
    "kubernetes.io/role/internal-elb"           = "1"
  }
}

# EKSクラスター
module "eks" {
  source  = "terraform-aws-modules/eks/aws"
  version = "19.15.3"

  cluster_name    = var.cluster_name
  cluster_version = "1.28"

  vpc_id                         = module.vpc.vpc_id
  subnet_ids                     = module.vpc.private_subnets
  cluster_endpoint_public_access = true

  eks_managed_node_group_defaults = {
    instance_types = ["t3.medium"]
  }

  eks_managed_node_groups = {
    main = {
      name = "node-group-1"

      instance_types = ["t3.medium"]

      min_size     = 2
      max_size     = 10
      desired_size = 3

      pre_bootstrap_user_data = <<-EOT
        echo 'net.ipv4.ip_forward = 1' >> /etc/sysctl.conf
        sysctl -p
      EOT
    }
  }

  # OIDC Provider for IRSA
  enable_irsa = true

  # クラスターアドオン
  cluster_addons = {
    coredns = {
      most_recent = true
    }
    kube-proxy = {
      most_recent = true
    }
    vpc-cni = {
      most_recent = true
    }
  }

  tags = var.tags
}

# ALB Controller用のIRSA
module "load_balancer_controller_irsa" {
  source  = "terraform-aws-modules/iam/aws//modules/iam-role-for-service-accounts-eks"
  version = "5.30.0"

  role_name = "${var.cluster_name}-aws-load-balancer-controller"

  attach_load_balancer_controller_policy = true

  oidc_providers = {
    main = {
      provider_arn               = module.eks.oidc_provider_arn
      namespace_service_accounts = ["kube-system:aws-load-balancer-controller"]
    }
  }
}

# Helm provider設定
provider "helm" {
  kubernetes {
    host                   = module.eks.cluster_endpoint
    cluster_ca_certificate = base64decode(module.eks.cluster_certificate_authority_data)

    exec {
      api_version = "client.authentication.k8s.io/v1beta1"
      command     = "aws"
      args = ["eks", "get-token", "--cluster-name", var.cluster_name]
    }
  }
}

# AWS Load Balancer Controller
resource "helm_release" "aws_load_balancer_controller" {
  name       = "aws-load-balancer-controller"
  repository = "https://aws.github.io/eks-charts"
  chart      = "aws-load-balancer-controller"
  namespace  = "kube-system"
  version    = "1.6.0"

  set {
    name  = "clusterName"
    value = var.cluster_name
  }

  set {
    name  = "serviceAccount.create"
    value = "true"
  }

  set {
    name  = "serviceAccount.annotations.eks\\.amazonaws\\.com/role-arn"
    value = module.load_balancer_controller_irsa.iam_role_arn
  }

  depends_on = [
    module.eks
  ]
}

Kubernetes マニフェストとGitOps

# kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

namespace: production

resources:
  - deployment.yaml
  - service.yaml
  - ingress.yaml
  - configmap.yaml
  - hpa.yaml

configMapGenerator:
  - name: app-config
    envs:
      - config.env

secretGenerator:
  - name: app-secrets
    envs:
      - secrets.env

patchesStrategicMerge:
  - replica-patch.yaml

images:
  - name: myapp
    newName: ghcr.io/myorg/myapp
    newTag: v1.2.3

---
# argocd-application.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: production-app
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/myorg/k8s-configs
    targetRevision: HEAD
    path: apps/production
  destination:
    server: https://kubernetes.default.svc
    namespace: production
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
    syncOptions:
    - CreateNamespace=true
    retry:
      limit: 5
      backoff:
        duration: 5s
        factor: 2
        maxDuration: 3m

Prometheus による監視設定

# prometheus-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: prometheus-config
data:
  prometheus.yml: |
    global:
      scrape_interval: 15s
      evaluation_interval: 15s

    alerting:
      alertmanagers:
        - static_configs:
            - targets:
              - alertmanager:9093

    rule_files:
      - /etc/prometheus/rules/*.yml

    scrape_configs:
      - job_name: 'kubernetes-apiservers'
        kubernetes_sd_configs:
          - role: endpoints
        scheme: https
        tls_config:
          ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
        bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
        relabel_configs:
          - source_labels: [__meta_kubernetes_namespace, __meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name]
            action: keep
            regex: default;kubernetes;https

      - job_name: 'kubernetes-nodes'
        kubernetes_sd_configs:
          - role: node
        scheme: https
        tls_config:
          ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
        bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
        relabel_configs:
          - action: labelmap
            regex: __meta_kubernetes_node_label_(.+)

      - job_name: 'kubernetes-pods'
        kubernetes_sd_configs:
          - role: pod
        relabel_configs:
          - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
            action: keep
            regex: true
          - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path]
            action: replace
            target_label: __metrics_path__
            regex: (.+)
          - source_labels: [__address__, __meta_kubernetes_pod_annotation_prometheus_io_port]
            action: replace
            regex: ([^:]+)(?::\d+)?;(\d+)
            replacement: $1:$2
            target_label: __address__

---
# alert-rules.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: prometheus-rules
data:
  node-alerts.yml: |
    groups:
      - name: node-alerts
        interval: 30s
        rules:
          - alert: NodeCPUHigh
            expr: 100 - (avg by (instance) (irate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 80
            for: 5m
            labels:
              severity: warning
            annotations:
              summary: "Node CPU usage is high"
              description: "CPU usage is above 80% (current value: {{ $value }}%)"
          
          - alert: NodeMemoryHigh
            expr: (1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) * 100 > 85
            for: 5m
            labels:
              severity: warning
            annotations:
              summary: "Node memory usage is high"
              description: "Memory usage is above 85% (current value: {{ $value }}%)"

シェルスクリプトによる自動化

#!/bin/bash
# deploy.sh - 自動デプロイメントスクリプト

set -euo pipefail

# 変数定義
NAMESPACE="${NAMESPACE:-production}"
APP_NAME="${APP_NAME:-myapp}"
IMAGE_TAG="${IMAGE_TAG:-latest}"
TIMEOUT="${TIMEOUT:-300}"

# 関数定義
log() {
    echo "[$(date +'%Y-%m-%d %H:%M:%S')] $*"
}

error() {
    log "ERROR: $*" >&2
    exit 1
}

# 前提条件チェック
check_prerequisites() {
    log "Checking prerequisites..."
    
    command -v kubectl >/dev/null 2>&1 || error "kubectl is not installed"
    command -v helm >/dev/null 2>&1 || error "helm is not installed"
    
    kubectl cluster-info >/dev/null 2>&1 || error "Cannot connect to Kubernetes cluster"
    
    log "Prerequisites check passed"
}

# デプロイメント実行
deploy_application() {
    log "Starting deployment of ${APP_NAME} with tag ${IMAGE_TAG}..."
    
    # Namespace作成(存在しない場合)
    kubectl create namespace "${NAMESPACE}" --dry-run=client -o yaml | kubectl apply -f -
    
    # ConfigMapとSecret更新
    kubectl apply -f configs/ -n "${NAMESPACE}"
    
    # Helmチャートでデプロイ
    helm upgrade --install "${APP_NAME}" ./charts/"${APP_NAME}" \
        --namespace "${NAMESPACE}" \
        --set image.tag="${IMAGE_TAG}" \
        --set replicaCount=3 \
        --wait \
        --timeout="${TIMEOUT}s"
    
    log "Deployment completed successfully"
}

# ヘルスチェック
health_check() {
    log "Performing health check..."
    
    # Deploymentの状態確認
    kubectl rollout status deployment/"${APP_NAME}" -n "${NAMESPACE}" --timeout="${TIMEOUT}s"
    
    # Podの準備状態確認
    ready_pods=$(kubectl get pods -n "${NAMESPACE}" -l app="${APP_NAME}" -o json | jq '.items | map(select(.status.conditions[] | select(.type=="Ready" and .status=="True"))) | length')
    total_pods=$(kubectl get pods -n "${NAMESPACE}" -l app="${APP_NAME}" -o json | jq '.items | length')
    
    if [[ "${ready_pods}" -ne "${total_pods}" ]]; then
        error "Not all pods are ready: ${ready_pods}/${total_pods}"
    fi
    
    log "Health check passed: ${ready_pods}/${total_pods} pods are ready"
}

# メイン処理
main() {
    log "Deployment script started"
    
    check_prerequisites
    deploy_application
    health_check
    
    log "Deployment completed successfully!"
}

# スクリプト実行
main "$@"