6
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Limaで構築するLinux実習環境:Macユーザー向け解説

Last updated at Posted at 2025-12-04

最初に

 朝日新聞社の秋田です。若手社員の研修を担当しています。IT全般でいろんな研修をしていますが、主には新人が対象なので浅く広く教えています。
 新人研修ではLinuxの実習をしています。新人にはMacが貸与されておりmacOSはUnix系でLinuxに近い環境ですが、より実践的なLinux操作を学ぶため、仮想マシンでLinuxを動かすことにしました。この環境構築には軽量な仮想化ツールであるlimaを使用し、Mac上で簡単にLinuxを利用できる仕組みを実現しました。

 limaでは、仮想マシンの設定や起動をyamlファイルで指定します。今回このyamlを作成する過程で、思いがけない発見や驚きがあったので紹介します。

 limaを使った背景や、yamlを作るためにサーバーの仕様を検討する過程などは、後段に記します。

おどろき一覧

システムの仕様

Linuxサーバー仕様(仮想マシンの構成)

  • OS: AlmaLinux 10
  • 仮想CPU: 2
  • メモリー: 2GB
  • swap領域: 2GB
  • ストレージ: 12GB
  • SSHログイン: SSHコマンドを使う。個人ユーザーIDはlimauserでパスワードはLima#Alma10、接続ポートは2222/tcp
  • HTTP接続: 8000/tcp
  • アクセス制限: 個人のMacからのみアクセス可能
  • ディレクトリー共有:/var/www/htmlとMacの~/liimaParts/shareフォルダーを共有
  • アプリケーション: phpMyAdminが動く

 ※パスワードを忘れて実習が中断するのを避けるため、覚えやすいパスワードを設定しています。

使ったMacの仕様

  • ハードウェア: MacBook Air (M2)
  • メモリー: 16GB
  • ストレージ: 512GB
  • OS: macOS Tahoe
  • lima: version 2.0.1

 Macには次のようなディレクトリー構成を作って、limaに関するファイルを保存しました。

Macのディレクトリー構造
~/                     #Macのホームディレクトリー
|--limaParts           
|  |--keys             #SSHで使う鍵
|  |--limaYaml         #yamlファイル
|  |--limaImage        #ダウンロードファイル
|  |--share            #Macとvm間でファイル交換用

Linux vmを作成

 これまでサーバーと書いていましたが、以降はvmにします。Virtual Machineの略です。ゲストOSと呼ぶのが一般的かもしれません。この場合はmacOSをホストOSと呼びます。今回はMacやmacOSとしています。

yamlファイルの作成

 vm(仮想マシン)の作成は、まずその仕様をyaml形式で定義します。limaは、このyamlファイルの内容に従ってvmを構築します。つまりyamlファイルを作成すること自体が、vmの設計と構築のプロセスになります。

 yamlファイルの作成には、CursorとCopilot、本家のドキュメント https://lima-vm.io/docs/usage/https://github.com/lima-vm/lima 、この他qiitaはもちろんzennなどの書き込みにお世話になりました。

 yamlには色々設定できるようです。しかし希望のvmを作ることに専念しました。
 目指すvmのために設定するには、この辺りのセクションを使います。

vmType:
cpus:
memory:
disk:
images:
ssh:
mounts:
portForwards:
rosetta:
provision:

 provisionは、vmができあがった後で実行するコマンド群です。EC2やterraformと同じですね。

最初の試み

 まずはマニュアルを読まない手抜きで、Cursorに目指したLinux環境と使ったMacの情報を与えてyamlを作ってもらいました。

# AlmaLinux 10 on Lima with VZ (Virtualization Framework)
vmType: vz
    
***中略***

# ポートフォワーディング設定
portForwards:
  # SSH接続用(2222/tcp)
  - guestPort: 22
    hostPort: 2222
    proto: tcp
    guestIP: "127.0.0.1"
    hostIP: "127.0.0.1"
    
***中略***

# プロビジョニング設定
provision:
  # システム用プロビジョニング(rootユーザーで実行)
  - mode: system
    script: |

***中略***
      
      # limauserユーザーの作成
      if ! id -u limauser > /dev/null 2>&1; then
        echo "Creating limauser..."
        useradd -m -s /bin/bash limauser
        echo "limauser:Lima#Alma10" | chpasswd
        
        # sudoers設定
        echo "limauser ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/limauser
        chmod 440 /etc/sudoers.d/limauser
        
        # /var/www/html へのアクセス権限設定
        chown -R limauser:limauser /var/www/html
      fi

***後略***

 やった〜完成!
 早速、起動しました。

akita@XXXXXXXXXX ~ % limactl start ~/limaParts/limaYaml/alma10.yaml --name alma10
? Creating an instance "alma0" Proceed with the current configuration
FATA[0001] the YAML is invalid, saved the buffer as "lima.REJECTED.yaml": field `portForwards[0].guestPort` must not be 22
field `portForwards[0].guestPortRange[0]` must not be 22
field `portForwards[0].guestPortRange[1]` must not be 22 

 あかんやんか😡。
 Cursorに聞くと、「Lima ではSSHポートフォワーディングは自動的に管理されるため、portForwardsに含めてはいけません。SSHの設定は ssh: セクションで行います。」だそうです。

 などなど、知らないこと、マニュアルを読むのをサボったことなどが原因ですが、驚くことがありました。

今回作成したyamlの紹介

 色々苦労してyamlファイルを作りました。

できあがったYAMLファイルはこちらです(長いです)
alma10.yaml
# AlmaLinux 10 on Lima with VZ (Virtualization Framework)
# macOS(13.5以上)はvz
vmType: vz

# CPU設定(仮想CPU: 2コア)
# デフォルトは4 cores
cpus: 2

# メモリー設定(2GB)
# デフォルトは4GiB
memory: "2GiB"

# ディスク設定(12GB)
# デフォルトは100GiB
disk: "12GiB"

# AlmaLinux 10 GenericCloud images
# M2 Mac (Apple Silicon) では aarch64 イメージを使用
images:
  # aarch64 イメージ(Apple Silicon用)
  - location: "https://repo.almalinux.org/almalinux/10/cloud/aarch64/images/AlmaLinux-10-GenericCloud-latest.aarch64.qcow2"
    arch: "aarch64"
  # x86_64 イメージ(Intel Mac用)
  #- location: "https://repo.almalinux.org/almalinux/10/cloud/x86_64/images/AlmaLinux-10-GenericCloud-latest.x86_64.qcow2"
  #  arch: "x86_64"

  # ローカルイメージを使う場合
  # - location: "~/limaParts/limaImage/AlmaLinux-10-GenericCloud-10.0-20250528.0.aarch64.qcow2"
  #   arch: "aarch64"

# SSH設定
ssh:
  localPort: 2222
  # 公開鍵認証を有効化(パスワード認証は無効化)
  # loadDotSSHPubKeys: true
  forwardAgent: false

# 共有ディレクトリー(ホスト→ゲスト)
mounts:
  # ホームディレクトリー全体は参照のみ
  # writable: trueを指定しない場合はReadOnly
  # mountの必要はないが、limactl shellコマンドでエラーが出ないようにするために残しておく
  - location: "~"
    writable: false

  # macOS: /Users/akita/limaParts/share をゲストの /var/www/html へ 
  - location: "~/limaParts/share"
    mountPoint: "/var/www/html"
    writable: true

  # macOS: /Users/akita/limaParts/keys をゲストの /mnt/keys へ 
  - location: "~/limaParts/keys"
    mountPoint: "/mnt/keys"
    writable: false

  # 一時ディレクトリーは共有しない
  # - location: "{{.GlobalTempDir}}/lima"
  #   mountPoint: /tmp/lima
  #   writable: true

# ポートフォワード設定
portForwards:
    # HTTP をホスト 8000 へフォワード(任意)
    - guestPort: 80
      hostPort: 8000
      # defaultは127.0.0.1にバインドしている。他のpcからアクセスできるようにするには、0.0.0.0を追加
      # hostIP: "0.0.0.0"


# Rosetta 2 を有効化(ARM上でx86_64バイナリを実行可能)
rosetta:
  enabled: true

# プロビジョニング(初期設定)
provision:
  - mode: system
    script: |
      # 基本設定のみ(タイムゾーン、ユーザー、SSH)
      # タイムゾーンをTokyoに設定
      timedatectl set-timezone Asia/Tokyo || true
      echo "Timezone set to Asia/Tokyo"
      
      # SELinuxをdisabledに設定
      setenforce 0 || true
      sed -i 's/SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config || true

      # swap領域を作る
      # ddコマンドでストレージに2GBのswap用の領域を準備
      sudo dd if=/dev/zero of=/swap bs=1M count=2048
      # swap領域に変換
      sudo mkswap /swap; sudo chmod 0600 /swap; sudo swapon /swap
      # できあがり
      free
      # 自動mout
      sudo cp -p /etc/fstab /etc/fstab.org
      sudo sh -c "echo '/swap        swap       swap    defaults        0   0' >> /etc/fstab"
      cat /etc/fstab

      # 全ユーザーのsubuid/subgid範囲を65536に調整
      echo "Adjusting all users' subuid/subgid ranges to 65536"
      
      # /etc/subuidを処理
      if [ -f /etc/subuid ]; then
        cp /etc/subuid /etc/subuid.bak
        awk -F: '{
          if (NF == 3) {
            # ユーザー名:開始値:範囲数 の形式
            # 範囲数を65536に変更
            print $1":"$2":65536"
          } else {
            print $0
          }
        }' /etc/subuid.bak > /etc/subuid
        echo "Updated /etc/subuid - all ranges set to 65536"
      fi
      
      # /etc/subgidを処理
      if [ -f /etc/subgid ]; then
        cp /etc/subgid /etc/subgid.bak
        awk -F: '{
          if (NF == 3) {
            # ユーザー名:開始値:範囲数 の形式
            # 範囲数を65536に変更
            print $1":"$2":65536"
          } else {
            print $0
          }
        }' /etc/subgid.bak > /etc/subgid
        echo "Updated /etc/subgid - all ranges set to 65536"
      fi
      
      # limauserユーザーの作成
      if ! id limauser >/dev/null 2>&1; then
        echo "Creating limauser..."
        useradd limauser
        echo "limauser:Lima#Alma10" | chpasswd || true
        echo "Created limauser user"
      fi

      # wheel グループに追加(sudo権限)
      if getent group wheel >/dev/null 2>&1; then
        gpasswd -a limauser wheel || true
      fi

      # wheelグループのパスワードなしsudo設定
      echo "%wheel ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers.d/wheel
      chmod 440 /etc/sudoers.d/wheel

      # SSH公開鍵の設定
      if [ -f /mnt/keys/limauser_user.pub ]; then
        # limauserユーザーの.sshディレクトリーを作成
        mkdir -p /home/limauser/.ssh
        chown limauser:limauser /home/limauser/.ssh
        chmod 700 /home/limauser/.ssh
        
        # 公開鍵をauthorized_keysに追加
        cp /mnt/keys/limauser_user.pub /home/limauser/.ssh/authorized_keys
        chown limauser:limauser /home/limauser/.ssh/authorized_keys
        chmod 600 /home/limauser/.ssh/authorized_keys
      fi

      # SSH設定で公開鍵認証を有効化
      sed -i 's/#PubkeyAuthentication yes/PubkeyAuthentication yes/' /etc/ssh/sshd_config || true
      sed -i 's/PubkeyAuthentication no/PubkeyAuthentication yes/' /etc/ssh/sshd_config || true
      
      # パスワード認証も有効化(フォールバック用)
      sed -i 's/#PasswordAuthentication yes/PasswordAuthentication yes/' /etc/ssh/sshd_config || true
      sed -i 's/PasswordAuthentication no/PasswordAuthentication yes/' /etc/ssh/sshd_config || true

      # ホストキーの設定(毎回同じキーを使用)
      if [ -f /mnt/keys/alma10_host.priv ]; then
        # SSHホストキーディレクトリーの確認
        mkdir -p /etc/ssh
        
        # 元の名前のままコピー
        cp /mnt/keys/alma10_host.priv /etc/ssh/alma10_host.priv
        chmod 600 /etc/ssh/alma10_host.priv
        chown root:root /etc/ssh/alma10_host.priv
        
        # 公開鍵もコピー(存在する場合)
        if [ -f /mnt/keys/alma10_host.pub ]; then
          cp /mnt/keys/alma10_host.pub /etc/ssh/alma10_host.pub
          chmod 644 /etc/ssh/alma10_host.pub
          chown root:root /etc/ssh/alma10_host.pub
        fi
        
        # sshd_configでカスタムホストキーを指定
        echo "HostKey /etc/ssh/alma10_host.priv" >> /etc/ssh/sshd_config
        
        echo "Host key configured from /mnt/keys/alma10_host.priv (using original name)"
      fi

      # /var/www/html は共有ディレクトリーのため所有者変更は不要

      # SSH設定を再読み込み
      systemctl restart sshd || true

  - mode: system
    script: |
      # アプリケーション設定(Apache、MariaDB、phpMyAdmin)
      sudo yum install -y httpd

      #configの元ファイルを保存
      sudo cp -p /etc/httpd/conf/httpd.conf /etc/httpd/conf/httpd.conf.org

      #元ファイルから/var/www/htmlのAllowOverrideを変更
      awk '/<Directory "\/var\/www\/html">/{f=1} f==1 && /AllowOverride None/{sub(/AllowOverride None/,"AllowOverride All "); f=0} 1' /etc/httpd/conf/httpd.conf.org | sudo tee /etc/httpd/conf/httpd.conf

      #変更箇所を表示
      diff /etc/httpd/conf/httpd.conf /etc/httpd/conf/httpd.conf.org

      #httpd.confの構成チェック
      apachectl configtest

      # apacheを自動起動
      sudo systemctl enable httpd.service

      # apacheを起動
      sudo systemctl start httpd.service

      # apacheの状態を確認
      #sudo systemctl status httpd.service

      # mariaDBの導入
      # mariaのバージョンは11.8、OSのバージョンは10で設定
      cat << EOF | sudo tee /etc/yum.repos.d/MariaDB.repo
      # https://mariadb.org/download/
      [mariadb]
      name = MariaDB
      # rpm.mariadb.org is a dynamic mirror if your preferred mirror goes offline. See https://mariadb.org/mirrorbits/ for details.
      baseurl = https://rpm.mariadb.org/11.8/rhel/\$releasever/\$basearch
      # baseurl = https://ftp.yz.yamagata-u.ac.jp/pub/dbms/mariadb/yum/11.8/rhel/10/aarch64
      gpgkey = https://rpm.mariadb.org/RPM-GPG-KEY-MariaDB
      # gpgkey = https://ftp.yz.yamagata-u.ac.jp/pub/dbms/mariadb/yum/RPM-GPG-KEY-MariaDB
      gpgcheck = 1
      EOF

      sudo dnf install -y MariaDB-server MariaDB-client


      # mariadbを自動起動
      sudo systemctl enable mariadb

      # mariadbを起動
      sudo systemctl start mariadb

      # mariadbのユーザー作成
      cat << EOF > maridb_user_create.sql
      # ユーザー作成
      CREATE USER 'dbuser'@'localhost' IDENTIFIED BY 'dbpass';
      GRANT ALL PRIVILEGES ON * . * TO 'dbuser'@'localhost';
      FLUSH PRIVILEGES;
      EOF

      sudo mysql -u root < maridb_user_create.sql

      # rootのパスワード設定
      cat << EOF > maridb_init.sql
      # パスワード設定
      ALTER USER 'root'@'localhost' IDENTIFIED BY 'root';
      exit
      EOF

      sudo mysql -u root < maridb_init.sql

      #sudo dnf install -y php
      sudo dnf install -y php php-mysqlnd php-gd 

      #apache再起動
      sudo systemctl restart httpd

      # phpMyAdminインストール
      #phpMyAdminをダウンロード
      curl -O https://files.phpmyadmin.net/phpMyAdmin/5.2.3/phpMyAdmin-5.2.3-all-languages.tar.gz
      tar xfz phpMyAdmin-5.2.3-all-languages.tar.gz
      #tar xvfz phpMyAdmin-5.2.3-all-languages.tar.gz
      sudo mv phpMyAdmin*-all-languages /usr/share/phpMyAdmin
      sudo chown -R apache:apache /usr/share/phpMyAdmin
      sudo ls -l /usr/share | grep phpMyAdmin

      cat << EOF | sudo tee /etc/httpd/conf.d/phpMyAdmin.conf
      # phpMyAdmin - Web based MySQL browser written in php
      #
      # Allows only localhost by default
      #
      # But allowing phpMyAdmin to anyone other than localhost should be considered
      # dangerous unless properly secured by SSL

      Alias /phpMyAdmin /usr/share/phpMyAdmin
      Alias /phpmyadmin /usr/share/phpMyAdmin

      <Directory /usr/share/phpMyAdmin/>
        AddDefaultCharset UTF-8

        <IfModule mod_authz_core.c>
          # Apache 2.4
          <RequireAny>
          # Require ip 127.0.0.1
          # Require ip ::1
          Require all granted
          </RequireAny>
        </IfModule>
        <IfModule !mod_authz_core.c>
          # Apache 2.2
          Order Deny,Allow
          Deny from All
          Allow from 127.0.0.1
          Allow from ::1
        </IfModule>
      </Directory>

      <Directory /usr/share/phpMyAdmin/setup/>
        <IfModule mod_authz_core.c>
          # Apache 2.4
          <RequireAny>
          # Require ip 127.0.0.1
          # Require ip ::1
          Require all granted
          </RequireAny>
        </IfModule>
        <IfModule !mod_authz_core.c>
          # Apache 2.2
          Order Deny,Allow
          Deny from All
          Allow from 127.0.0.1
          Allow from ::1
        </IfModule>
      </Directory>

      # These directories do not require access over HTTP - taken from the original
      # phpMyAdmin upstream tarball
      #
      <Directory /usr/share/phpMyAdmin/libraries/>
        <IfModule mod_authz_core.c>
          # Apache 2.4
          Require all denied
        </IfModule>
        <IfModule !mod_authz_core.c>
          # Apache 2.2
          Order Deny,Allow
          Deny from All
          Allow from None
        </IfModule>
      </Directory>

      <Directory /usr/share/phpMyAdmin/setup/lib/>
        <IfModule mod_authz_core.c>
          # Apache 2.4
          Require all denied
        </IfModule>
        <IfModule !mod_authz_core.c>
          # Apache 2.2
          Order Deny,Allow
          Deny from All
          Allow from None
        </IfModule>
      </Directory>

      <Directory /usr/share/phpMyAdmin/setup/frames/>
        <IfModule mod_authz_core.c>
          # Apache 2.4
          Require all denied
        </IfModule>
        <IfModule !mod_authz_core.c>
          # Apache 2.2
          Order Deny,Allow
          Deny from All
          Allow from None
        </IfModule>
      </Directory>

      # This configuration prevents mod_security at phpMyAdmin directories from
      # filtering SQL etc.  This may break your mod_security implementation.
      #
      #<IfModule mod_security.c>
      #    <Directory /usr/share/phpMyAdmin/>
      #        SecRuleInheritance Off
      #    </Directory>
      #</IfModule>
      EOF

      # phpMyAdmin設定ファイルのコピー
      sudo cp -p /usr/share/phpMyAdmin/config.sample.inc.php /usr/share/phpMyAdmin/config.inc.php

      # クッキー暗号化の対応
      # phpMyAdminの暗号化キー(blowfish_secret)を生成して設定
      # 32バイトのキーを生成(openssl rand -hex 16で16文字発生させ、1文字が2バイトなので32バイトの文字列を生成)
      BLOWFISH_SECRET=$(openssl rand -hex 16)
      # blowfish_secretの設定を更新(空文字列または既存の値を置換)
      sudo sed -i "s|\\\$cfg\['blowfish_secret'\] = .*;|\\\$cfg['blowfish_secret'] = '${BLOWFISH_SECRET}';|" /usr/share/phpMyAdmin/config.inc.php

      # phpMyAdmin 環境保管領域の設定
      # phpMyAdmin設定ファイルを修正前にコピー
      sudo cp -p /usr/share/phpMyAdmin/config.inc.php /usr/share/phpMyAdmin/config.inc.php.org

      # phpMyAdminのStorage databaseとテーブルを作成
      sudo mysql -u root -proot < /usr/share/phpMyAdmin/sql/create_tables.sql
      
      # Storage database and tables から End of servers configuration までのコメントアウトを外す
      sudo awk '
        BEGIN {include = 0; }
          # 開始マーカーに到達
          /Storage database and tables/ {
            include=1; print; next; } 
          # 終了マーカーに到達
          include &&  /End of servers configuration/ {
            include= 0 ; print; next; } 
          # 区間内の通常行:行頭の // を外す(先頭の空白は維持)
          include {
            if (match($0, /^([[:space:]]*)\/\/(.+)/, arr)) {
              $0 = arr[1] arr[2]
            }
            print; next } ; 
          # それ以外は素通し
          { print }
      ' /usr/share/phpMyAdmin/config.inc.php.org | sudo tee /usr/share/phpMyAdmin/config.inc.php

      sudo diff /usr/share/phpMyAdmin/config.inc.php.org /usr/share/phpMyAdmin/config.inc.php

      httpd -t

      sudo systemctl restart httpd

  - mode: system
    script: |
      # firewalldのインストールと設定
      sudo dnf install -y firewalld
      
      # firewalldを自動起動
      sudo systemctl enable firewalld
      
      # firewalldを起動
      sudo systemctl start firewalld
      
      # public zoneをデフォルトに設定
      sudo firewall-cmd --set-default-zone=public
      
      # 現在のゾーンを確認
      sudo firewall-cmd --get-active-zones
      
      # public zoneの既存サービスをすべて削除
      sudo firewall-cmd --zone=public --remove-service=ssh --permanent
      sudo firewall-cmd --zone=public --remove-service=http --permanent
      sudo firewall-cmd --zone=public --remove-service=https --permanent
      sudo firewall-cmd --zone=public --remove-service=dhcpv6-client --permanent
      
      # public zoneにlocalhostからのアクセスを許可(IPアドレス制限)
      sudo firewall-cmd --zone=public --add-source=127.0.0.1/32 --permanent
      
      # public zoneにSSHサービスを許可
      sudo firewall-cmd --zone=public --add-service=ssh --permanent
      
      # public zoneにHTTPサービスを許可
      sudo firewall-cmd --zone=public --add-service=http --permanent
      
      # public zoneにHTTPSサービスを許可
      sudo firewall-cmd --zone=public --add-service=https --permanent
      
      # 設定を再読み込み
      sudo firewall-cmd --reload
      
      # public zoneの設定を確認
      sudo firewall-cmd --zone=public --list-all
      
      # ファイアウォールの状態を確認
      sudo systemctl status firewalld

 完成したyamlを眺めながら、意外な事実に驚かされたことなどを紹介します。

vmType

 Apple Siliconでは、基本はvmTypeにmacOSのVirtualization.Frameworkである「vz」を指定します。エミュレータ型の仮想化ソフトの「qemu」でもいいのですが、パフォーマンスが落ちるようです。「qemu」を指定するときはrosettaも必要です。

# VM 基本設定
# macOS(13.5以上)はvz
vmType: "vz"

vmのシステムスペック

 limaのデフォルトは、潤沢な資源の割り当てになっています。
 このvmはLinuxコマンドの実習にしか使わないので、Mac本体への影響を少なくするために、適切な値を指定しました。

【次の記事を参考にしています】
lima Docs:Configuration guide

# CPU設定(仮想CPU: 2コア)
# デフォルトは4 cores
cpus: 2

# メモリー設定(2GB)
# デフォルトは4GiB
memory: "2GiB"

# ディスク設定(12GB)
# デフォルトは100GiB
disk: "12GiB"

😯ディスクサイズをガチで確保

「おどろき一覧」にもどる

 これまでこの研修にはVirtualBoxを使っていました。VirtualBoxのVMDKファイルは、作成時に「仮想的な最大サイズ」を指定するのですが、実際にはゲストOSが使用している領域のファイルサイズでした。でもlimaはここで指定したサイズをガチで確保します。
 limaのvmのディスクはこれです。

ファイル名 用途 メモ
basedisk ベースイメージ
diffdisk 差分イメージ(QCOW2) diffdiskが重要で、vmのほとんどの内容がここに詰まっているようです

【次の記事を参考にしています】
Internal data structure

 実際に見てみると12GiBのファイルができています。

akita@XXXXXXXXXX alma10 % pwd
/Users/akita/.lima/alma10
akita@XXXXXXXXXX alma10 % ls -l
***中略***
-rw-r--r--  1 akita  staff    440926208 11月 12 17:30 basedisk
-rw-r--r--  1 akita  staff  12884901888 11月 15 10:06 diffdisk
***中略***
akita@XXXXXXXXXX alma10 % 

 ちなみにメモリーは、Mac全体16GBの0.2%で、必要な量だけを使っているようです。vmの使い方を間違えなければMacへの影響は少ないでしょう。

akita@XXXXXXXXXX alma10 % ps aux | awk 'NR==1 || /lima/ { print $4,$11,$12,$13};'   
%MEM COMMAND  
0.2 limactl shell alma0

😯limaのuninstallはvmやキャッシュファイルは消してくれない

「おどろき一覧」にもどる

 話は飛びますが、ディスク関連のお話です。
 limaが不要になった場合はuninstallすればいいのですが、残骸が残ります。残骸はvm関連のファイルとOSなどのイメージで、不要なので消しましょう。
 消し方です。

limactl rm -f $(limactl ls -q)
rm -rf ~/.lima ~/Library/Caches/lima
brew uninstall lima

SSHのポート

 SSH接続は共通のuserIDで、ポート2222で接続を目指しています。

# SSH設定
ssh:
  localPort: 2222
  # 公開鍵認証を有効化(パスワード認証は無効化)
  # loadDotSSHPubKeys: true
  forwardAgent: false

 ssh:セクションでポートを指定します。こうするとlimaがランダムに変えていたポートが2222に固定されます。

akita@XXXXXXXXXX ~ % limactl ls
NAME           STATUS     SSH               CPUS    MEMORY    DISK
al110          Running    127.0.0.1:2222    2       2GiB      12GiB

😯SSHの22ポートはポートフォワードできません

「おどろき一覧」にもどる

 実は当初、22/tcpを2222/tcpにポートフォワードすればいいと思って、こんな設定をしました。でもエラーになります。

portForwards:
  # SSH接続用(2222/tcp)
  - guestPort: 22
    hostPort: 2222
    proto: tcp
    guestIP: "127.0.0.1"
    hostIP: "127.0.0.1"

 limaではSSHポートフォワードは管理されるため、portForwardsではなく、ssh:セクションで行わないといけないそうです。
 vm作成時に、こんなエラーが出ます。

FATA[0001] the YAML is invalid, saved the buffer as "lima.REJECTED.yaml": field `portForwards[0].guestPort` must not be 22
field `portForwards[0].guestPortRange[0]` must not be 22
field `portForwards[0].guestPortRange[1]` must not be 22 

SSHのログイン設定

 パスワード認証でログインしたくて、いろいろ試しましたが断念して公開鍵認証にしました。そこでMacの~/limaParts/keysを共有ディレクトリーにして、provisionセクションに公開鍵認証でログインするための公開鍵をvmに仕込んでいます。
 yamlの、この部分です。

      # SSH公開鍵の設定
      if [ -f /mnt/keys/limauser_user.pub ]; then
        # limauserユーザーの.sshディレクトリーを作成
        mkdir -p /home/limauser/.ssh
        chown limauser:limauser /home/limauser/.ssh
        chmod 700 /home/limauser/.ssh
        
        # 公開鍵をauthorized_keysに追加
        cp /mnt/keys/limauser_user.pub /home/limauser/.ssh/authorized_keys
        chown limauser:limauser /home/limauser/.ssh/authorized_keys
        chmod 600 /home/limauser/.ssh/authorized_keys
      fi

 これで、研修生全員がlimauser、ポート2222でSSHログインができるようになりました。SSHログインコマンドの構文は、
  ssh -i 秘密鍵 -p ポート番号 ユーザー名@ホスト名
なので、今の設定にしてログイン。/etc/os-releaseを確認すると、OS名がちゃんとAlmalinuxになっていますので、vmにちゃんとログインしたことを確認できます。

akita@XXXXXXXXXX ~ % ssh -i ~/limaParts/keys/limauser_user.priv -p 2222 limauser@localhost
The authenticity of host '[localhost]:2222 ([127.0.0.1]:2222)' can't be established.
ED25519 key fingerprint is SHA256:Qp0JPjUV4SDy8hN0bfuzx+F6XOU6vnfviXRuSdQhIj8.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '[localhost]:2222' (ED25519) to the list of known hosts.
[akita@lima-alma10 ~]$ cat /etc/os-release
NAME="AlmaLinux"
VERSION="10.0 (Purple Lion)"
ID="almalinux"
ID_LIKE="rhel centos fedora"
VERSION_ID="10.0"
PLATFORM_ID="platform:el10"
PRETTY_NAME="AlmaLinux 10.0 (Purple Lion)"
ANSI_COLOR="0;34"
LOGO="fedora-logo-icon"
CPE_NAME="cpe:/o:almalinux:almalinux:10::baseos"
HOME_URL="https://almalinux.org/"
DOCUMENTATION_URL="https://wiki.almalinux.org/"
VENDOR_NAME="AlmaLinux"
VENDOR_URL="https://almalinux.org/"
BUG_REPORT_URL="https://bugs.almalinux.org/"

ALMALINUX_MANTISBT_PROJECT="AlmaLinux-10"
ALMALINUX_MANTISBT_PROJECT_VERSION="10.0"
REDHAT_SUPPORT_PRODUCT="AlmaLinux"
REDHAT_SUPPORT_PRODUCT_VERSION="10.0"
SUPPORT_END=2035-06-01
[limauser@lima-alma10 ~]$ 

SSHログイン

 調子良くログインできました。ところが、面倒なことが起きました。
 このvmを止めて、再起動します。そしてログインすると、エラーになってログインできないのです。

akita@XXXXXXXXXX ~ % limactl stop alma10
***中略***
akita@XXXXXXXXXX ~ % limactl start alma10
***中略***

# SSHログイン
akita@XXXXXXXXXX ~ % ssh -i ~/limaParts/keys/limauser_user.priv -p 2222 limauser@localhost
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that a host key has just been changed.
The fingerprint for the ED25519 key sent by the remote host is
SHA256:hwsJG5QCfMxSTWWwoRH9EaALcvcqdDwDfO5iG4DOKWY.
Please contact your system administrator.
Add correct host key in /Users/akita/.ssh/known_hosts to get rid of this message.
Offending ECDSA key in /Users/akita/.ssh/known_hosts:3
Host key for [localhost]:2222 has changed and you have requested strict checking.
Host key verification failed.
akita@XXXXXXXXXX ~ % 

 ログインするときにホスト公開鍵が前回と違うので、中間者攻撃と判断してログインが失敗しているのです。
 サーバー認証をやめるか、~/.ssh/known_hostsの該当するレコードを削除すればログインできます。でもこのvmって初心者相手のLinux実習が目的です。初心者にはどちらも勧めることはできません。

 ここでSSHリモート接続フローのホスト認証を確認します。

 初回接続時は次の流れです。

  • クライアントがSSHサーバーに接続要求を送信する
  • SSHサーバーが接続要求を受け付けると、SSHサーバーのホスト公開鍵(ssh_host_rsa_key.pub)をクライアントに送信する
  • クライアントはホスト公開鍵からfingerprintを生成し、ユーザーに「Are you sure you want to continue connecting?」と確認を求める
  • ユーザーが正しいフィンガープリントであることを確認し、yes と入力するとホスト認証が完了する
  • ホスト認証が完了すると、ホスト公開鍵がクライアント側の~/.ssh/known_hostsファイルに格納される

 次回以降は、格納された公開鍵を参照してホスト認証が自動的に行われ、ユーザーへの確認が省略されます。

○次回以降

 フロー図はCopilotにmermaidコードを作ってもらったのを修正しました。

【次の記事を参考にしています】
LPIーJAPANのLinuCレベル1 技術解説セミナー2022/3/12 開催暗号の利用
【Linux】SSHの認証方式
実は8種類の鍵が使われている!?|SSH接続の流れ・仕組み」

😯limaはstart時にホスト鍵を再生成

「おどろき一覧」にもどる

 原因は、start時に新たにホストの鍵を再作成しているためです。このため再起動したときのホスト鍵は、start前のホスト鍵と異なっています。でもホストのipアドレスは常に127.0.0.1です。Mac側にはホストのipアドレスとホスト公開鍵の情報が登録されているのですが、この情報がstart前のvm(SSHサーバー)の状態になっているため、中間者攻撃と判断するのです。

 上図の「次回以降」の「送信してきた公開鍵が保存しているホスト公開鍵と一致することを確認」のところで、一致しないのでユーザー認証に進めなくなっているわけです。

 今の課題はこれです。

サーバー認証をやめるか、~/.ssh/known_hostsの該当するレコードを削除すればログインできます。でもこのvmって初心者相手のLinux実習が目的です。初心者にはどちらも勧めることはできません。

 これはstop/startでも毎回同じホスト鍵にすれば解決です。
 このように考えて、provisionに操作を追加しました。
 SSHログインと同じです。Macの~/limaParts/keysにホスト秘密鍵を保存して、provisionセクションで秘密鍵をvmに仕込んでいます。ついでなので公開鍵も登録しています。

      # ホストキーの設定(毎回同じキーを使用)
      if [ -f /mnt/keys/alma10_host.priv ]; then
        # SSHホストキーディレクトリーの確認
        mkdir -p /etc/ssh
        
        # 元の名前のままコピー
        cp /mnt/keys/alma10_host.priv /etc/ssh/alma10_host.priv
        chmod 600 /etc/ssh/alma10_host.priv
        chown root:root /etc/ssh/alma10_host.priv
        
        # 公開鍵もコピー(存在する場合)
        if [ -f /mnt/keys/alma10_host.pub ]; then
          cp /mnt/keys/alma10_host.pub /etc/ssh/alma10_host.pub
          chmod 644 /etc/ssh/alma10_host.pub
          chown root:root /etc/ssh/alma10_host.pub
        fi
        
        # sshd_configでカスタムホストキーを指定
        echo "HostKey /etc/ssh/alma10_host.priv" >> /etc/ssh/sshd_config
        
        echo "Host key configured from /mnt/keys/alma10_host.priv (using original name)"
      fi

 結果はこうなりました。
 初回は同じですが、stop/startの後からは、何かメッセージは出ているものの、ログインできるようになりました。

# 初回ログイン
akita@XXXXXXXXXX ~ % ssh -i ~/limaParts/keys/limauser_user.priv -p 2222 limauser@localhost 
The authenticity of host '[localhost]:2222 ([127.0.0.1]:2222)' can't be established.
ED25519 key fingerprint is SHA256:Qp0JPjUV4SDy8hN0bfuzx+F6XOU6vnfviXRuSdQhIj8.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '[localhost]:2222' (ED25519) to the list of known hosts.
[limauser@lima-alma10 ~]$ 
logout
Connection to localhost closed.

# 再起動
akita@XXXXXXXXXX ~ % limactl stop alma10
***中略***
akita@XXXXXXXXXX ~ % limactl start alma10
***中略***

# ログイン
akita@XXXXXXXXXX ~ % ssh -i ~/limaParts/keys/limauser_user.priv -p 2222 limauser@localhost
client_input_hostkeys: received duplicated ssh-ed25519 host key
Last login: Wed Nov 19 18:30:29 2025 from UNKNOWN
[limauser@lima-alma10 ~]$ uname -a
Linux lima-alma10 6.12.0-55.43.1.el10_0.aarch64 #1 SMP PREEMPT_DYNAMIC Thu Nov 13 14:57:02 EST 2025 aarch64 GNU/Linux
[limauser@lima-alma10 ~]$ 

ファイル共有

 今回はMacに次のようなファイル構成を作って、vmと共有しました。
用途は以下です。

~/                     #(共有・読み取り専用)Macのホームディレクトリー
|--limaParts           #(共有なし)
|  |--keys             #(共有・読み取り専用)SSHで使う鍵
|  |--limaYaml         #(共有なし)yamlファイル
|  |--limaImage        #(共有・読み取り専用)事前ダウンロードファイル
|  |--share            #(共有・編集可能)Macとvm間でファイル交換用

 vm側で領域が重ならないようにすれば、複数のディレクトリーをマウントできます。上の例だと、Mac側は、~(ホームディレクトリー)の中にlimaPartsがあって、その中にshareがあります。この状態をそのままvmにマウントできません。
 次のようにMacの〜はvmの/User/akitaにマウント、Macの~/shareはvmの/var/www/htmlにマウントするとvm側で領域は重なりません。
 次のようにディレクトリー共有の設定をしました。

# 共有ディレクトリー(ホスト→ゲスト)
mounts:
  # ホームディレクトリー全体は参照のみ
  # writable: trueを指定しない場合はReadOnly
 # mountの必要はないが、limactl shellコマンドでエラーが出ないようにするために残しておく
  - location: "~"
    writable: false

  # macOS: /Users/akita/limaParts/share をゲストの /var/www/html へ 
  - location: "~/limaParts/share"
    mountPoint: "/var/www/html"
    writable: true

  # macOS: /Users/akita/limaParts/keys をゲストの /mnt/keys へ 
  - location: "~/limaParts/keys"
    mountPoint: "/mnt/keys"
    writable: false

 今回はLinux実習が目的なので、Macのホームディレクトリーの共有は不要です。この部分 → - location: "~"
 ここはlimactl shellコマンドでログインしたとき、ローカルユーザーのホームディレクトリーではなく、このディレクトリーになります。このため、"~"のmountが無いとエラーメッセージが出るのです。デフォルトのパーミッションは編集不可ですが、そのことが分かるようにwritable: falseを付けています。

😯共有ディレクトリーの所有者はアクセスするユーザーで変わる

「おどろき一覧」にもどる

 今回は、共有ディレクトリーをvmのapacheのDocument rootにしています。所有者をapacheにしたいな〜と色々試して発見しました。
 アクセスするユーザーに応じて所有者が変わるのですね。

 試した結果です。
 /var/www/htmlが共有ディレクトリーです。rootで/var/www/htmlの所有者をみるとrootです。並びの/var/www/cgi-binもrootです。akitaユーザーに代わって確認します。/var/www/htmlの所有者はakitaに変わっています。でもcgi-binはrootのままです。

[root@lima-al10 ~]# whoami
root
[root@lima-al10 ~]# ls -l /var/www/
total 0
drwxr-xr-x. 2 root root   6 Jul 15 09:00 cgi-bin
drwxr-xr-x. 6 root root 192 Nov 12 18:08 html
[root@lima-al10 ~]# su - akita
Last login: Tue Nov 18 16:55:59 JST 2025 on pts/1
[akita@lima-al10 ~]$ whoami
akita
[akita@lima-al10 ~]$ ls -l /var/www/
total 0
drwxr-xr-x. 2 root  root    6 Jul 15 09:00 cgi-bin
drwxr-xr-x. 6 akita akita 192 Nov 12 18:08 html
[akita@lima-al10 ~]$ 

😯共有ディレクトリーのパーミッションはMacが支配

「おどろき一覧」にもどる

 共有ディレクトリーのパーミッションはMacのパーミッションになるようです。

 Macの~/limaParts/shareとvmの/var/www/htmlがディレクトリー共有の状態です。
 vmでパーミッション変更を試すとこうなりました。

[root@lima-al10 ~]# whoami
root

# rootが所有者。パーミッションは755。rootならなんでもできるハズ
[root@lima-al10 ~]# ls -l /var/www
total 0
drwxr-xr-x. 2 root root   6 Jul 15 09:00 cgi-bin
drwxr-xr-x. 6 root root 192 Nov 12 18:08 html

# パーミッションを変えてみたけど、rootだけどエラー
[root@lima-al10 ~]# chmod 775 /var/www/html
chmod: changing permissions of '/var/www/html': Operation not permitted

# でもディレクトリーの中では万能!
[root@lima-al10 ~]# touch /var/www/html/test.html
[root@lima-al10 ~]# ls -l /var/www/html/test.html
-rw-r--r--. 1 root root 0 Nov 18 17:31 /var/www/html/test.html
[root@lima-al10 ~]# chmod 664 /var/www/html/test.html
[root@lima-al10 ~]# ls -l /var/www/html/test.html
-rw-rw-r--. 1 root root 0 Nov 18 17:31 /var/www/html/test.html
[root@lima-al10 ~]# 

 次にMac側で操作を試します。

まずvmで見た時
# ~/var/www/htmlのパーミッションは755
[akita@lima-al10 alma10]$ ls -l /var/www/
total 0
drwxr-xr-x. 2 root  root    6 Jul 15 09:00 cgi-bin
drwxr-xr-x. 6 akita akita 192 Nov 12 18:08 html

 /var/www/htmlのパーミッションは755です。Macで、共有しているディレクトリーの~/limaParts/shareのパーミッションを775に変更します。

Macで操作
# ~/limaParts/shareのパーミッションは755
akita@XXXXXXXXXX % ls -l ~/limaParts 
drwxr-xr-x@  6 akita  staff    192 11月 12 18:08 share

# ~/limaParts/shareのパーミッションを755に変更
akita@XXXXXXXXXX % chmod 775 ~/limaParts/share 
akita@XXXXXXXXXX % ls -l ~/limaParts          
drwxrwxr-x@  6 akita  staff    192 11月 12 18:08 share

 vm側でもパーミッションは775に変わりました。

vmで見た時
# ~/var/www/htmlのパーミッションは775に変わった
[akita@lima-al10 alma10]$ ls -l /var/www/
total 0
drwxr-xr-x. 2 root  root    6 Jul 15 09:00 cgi-bin
drwxrwxr-x. 6 akita akita 192 Nov 12 18:08 html

ポートフォワード

 それほど意味はないのですが、vmの80/tcpをMac側で8000/tcpにポートフォワードしています。

# ポートフォワード設定
portForwards:
    # HTTP をホスト 8000 へフォワード(任意)
    - guestPort: 80
      hostPort: 8000
      # defaultは127.0.0.1にバインドしている。他のpcからアクセスできるようにするには、0.0.0.0を追加
      # hostIP: "0.0.0.0"

 yamlにコメントを入れていますが、ポートはデフォルトでは127.0.0.1にバインドしています。外部から来るパケットはNICのipアドレス宛てです。LISTENしている127.0.0.1はvm内部専用なので、外部からのパケットは届かない状態です。すなわち、このMacからしかアクセスできないということです。
 他のpcからアクセスできるようにするには、hostIP: "0.0.0.0"を追加する必要があります。

 vmのネットワークの様子です。全てのアドレスから80でLISTENしています。

[akita@lima-al10 alma10]$ ss -antl | awk 'NR==1 || /80|22/ {print;}'
State  Recv-Q Send-Q Local Address:Port  Peer Address:Port
LISTEN 0      80           0.0.0.0:3306       0.0.0.0:*   
LISTEN 0      128          0.0.0.0:22         0.0.0.0:*   
LISTEN 0      80              [::]:3306          [::]:*   
LISTEN 0      128             [::]:22            [::]:*   
LISTEN 0      511                *:80               *:*    

 Macの様子です。8000でLISTENだけど、127.0.0.1つまりMac自身の内部にバインドされています。

akita@XXXXXXXXXX ~ % netstat -an | awk 'NR==2 || (/LISTEN/ && /80|22/) {print}'  
Proto Recv-Q Send-Q  Local Address          Foreign Address        (state)    
tcp4       0      0  127.0.0.1.8000         *.*                    LISTEN     
tcp4       0      0  127.0.0.1.2222         *.*                    LISTEN     

ローカルユーザーの作成

 Linux研修用では、みんなが同じ環境でcdコマンドなどを体験したいのです。そのためにローカルユーザーを作って、全員がそのユーザーでログインして、同じコマンド、同じ構文で実習したいのです。またuseraddとかgroupaddとかも体験したいのです。

 というわけで共通のユーザーを作るために、provisionでuseraddをやりました。
 ここで問題が発生!

😯普通にvmを作るとローカルユーザーを作らせてくれない

「おどろき一覧」にもどる

 普通にvmを作ると、ローカルユーザーを作らせてくれませんでした。templateでAlmaLinuxを起動して試すと、useraddは失敗することが分かります。

akita@XXXXXXXXXX ~ % limactl start template://almalinux-10 --name=alma10-temp
***中略***
INFO[0115] READY. Run `limactl shell alma10-temp` to open the shell. 
akita@XXXXXXXXXX ~ % limactl shell alma10-temp

# ローカルユーザーを作らせてくれません。
[akita@lima-alma10-temp akita]$ sudo useradd hoge
useradd: Can't get unique subordinate UID range
useradd: can't create subordinate user IDs

 ここからはlimaは関係なく、Linuxの話です。

 Linuxカーネルには、名前空間(⁠Namespace)という機能があって、プロセスやリソースなどの資源を分離しています。仮想的な独立環境を作るための仕組みで、ある名前空間に所属する資源の処理内容が、名前空間が違う別の資源に対して影響を及ぼさないようにしているそうです。
 OSを起動しただけでは、全てのプロセスが同じ名前空間を共有しています。つまり分離はされていません。名前空間は、コンテナ技術(Docker、Podman)など「分離が必要なとき」に作られるそうです。

 素人なので正確さに欠ける場合があります。すみません🙇‍♂️。

 名前空間は、分離する資源ごとにMount名前空間、IPC名前空間、User名前空間のように複数あります。
 この中のUser名前空間では、サブUIDとサブGIDが使われます。それぞれの値は/etc/subuid、/etc/subgidで管理されています。
 このファイルは次の形式です。
 ユーザー名:開始UID:範囲サイズ
 例えばユーザーakitaの場合、/etc/subuid にakitaエントリが作られます。

akita:100000:65536|

 これらの値は、次の意味を持ちます。

akita:ホスト側のユーザー名
100000:ホスト側で割り当てる開始UID(サブUIDの開始番号)
65536:割り当てるUIDの数(範囲のサイズ)

 やっと本題に戻ります。

 vmの今の設定は以下です。

vmのUser Namespace
[akita@lima-alma10-temp akita]$ cat /etc/subuid
akita:524288:1073741824
[akita@lima-alma10-temp akita]$ cat /etc/subgid
akita:524288:1073741824

 ユーザーを追加すると、Linuxはユーザーごとに競合しないように順番にsubuidを増やしていきます。この値は、/etc/login.defsのSUB_UID_MIN、SUB_UID_MAX、SUB_UID_COUNTで決まるそうです。

[akita@lima-alma10 ~]$ grep SUB_UID /etc/login.defs 
SUB_UID_MIN		   524288
SUB_UID_MAX		600100000
SUB_UID_COUNT		    65536
[akita@lima-alma10 ~]$ 

 今の場合は、最初は524288になるようでakitaはそうなっています。1ユーザーあたりの割り当て範囲は65536ですが、実際は1073741824(約10億)となっています。
 次のユーザーを作るときは、最初のsubuidは、524288+65536になるはずですが、今回は524288+1073741824でSUB_UID_MAXの600100000(約6億)を超えます。
 このためローカルユーザーの作成に失敗していたようです。
 素人ですので、間違っていたらごめんなさい🙇‍♂️。

 現状の設定もですが、多くのディストリビューションではこの範囲は65536個(約6万)を割り当てるようです。そこで、provisionでこの範囲に変更しました。こうすることで、問題なくローカルユーザーを作ることができるようになりました。

      # 全ユーザーのsubuid/subgid範囲を65536に調整
      echo "Adjusting all users' subuid/subgid ranges to 65536"
      
      # /etc/subuidを処理
      if [ -f /etc/subuid ]; then
        cp /etc/subuid /etc/subuid.bak
        awk -F: '{
          if (NF == 3) {
            # ユーザー名:開始値:範囲数 の形式
            # 範囲数を65536に変更
            print $1":"$2":65536"
          } else {
            print $0
          }
        }' /etc/subuid.bak > /etc/subuid
        echo "Updated /etc/subuid - all ranges set to 65536"
      fi
      
      # /etc/subgidを処理
      if [ -f /etc/subgid ]; then
        cp /etc/subgid /etc/subgid.bak
        awk -F: '{
          if (NF == 3) {
            # ユーザー名:開始値:範囲数 の形式
            # 範囲数を65536に変更
            print $1":"$2":65536"
          } else {
            print $0
          }
        }' /etc/subgid.bak > /etc/subgid
        echo "Updated /etc/subgid - all ranges set to 65536"
      fi
      
      # limauserユーザーの作成
      if ! id limauser >/dev/null 2>&1; then
        echo "Creating limauser..."
        useradd limauser
        echo "limauser:Lima#Alma10" | chpasswd || true
        echo "Created limauser user"
      fi

      # wheel グループに追加(sudo権限)
      if getent group wheel >/dev/null 2>&1; then
        gpasswd -a limauser wheel || true
      fi

      # wheelグループのパスワードなしsudo設定
      echo "%wheel ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers.d/wheel
      chmod 440 /etc/sudoers.d/wheel

 ちなみに他の仮想化技術(VirtualBoxとUTM)でAlmaLinuxを試すと65536でした。AlmaLinuxのcloud-initイメージに誤りがあるのか、limaの何かが影響しているのかもしれません。

【次の記事を参考にしています】
Linuxカーネル4.1の名前空間(ドラフト)
コンテナの仕組みとLinuxカーネルのコンテナ機能[1]名前空間とは?
Separation Anxiety: A Tutorial for Isolating Your System with Linux Namespaces
23.3. 名前空間の概要
ルートレスコンテナーのユーザー名前空間について

provision

 provisionセクションでは、OSの設定やアプリケーションの導入を指示しています。
 長くなったので分かりやすくするために、- mode: systemを、基本設定、アプリケーション設定、firewalldのインストールと設定の3部にわけました。
普通のことなので説明は割愛します。

基本設定のみ(タイムゾーン、ユーザー、SSH)

  • タイムゾーンをTokyoに設定
  • SELinuxをdisabledに設定
  • swap領域を作って自動マウントに設定
  • sshdの設定
  • ユーザー作成

アプリケーション設定(Apache、MariaDB、phpMyAdmin)

  • apacheをインストール、httpd.confを変更、自動起動に設定
  • mariaDBをインストール、mariadbのユーザー作成、rootのパスワードを設定、自動起動に設定
  • phpをインストール
  • phpMyAdminをインストール、apacheのconfigファイルを作成、クッキー暗号化の対応、phpMyAdmin 環境保管領域の設定

firewalldのインストールと設定

  • firewalldをインストール、ルールを設定、自動起動に設定

 firewalldについては、limaはデフォルトではlistenポートを127.0.0.1にバインドしているので、実質的には無くてもいいかもしれません。でもLinux実習用なので起動させています。

yamlの説明はここまで

 長くなりましたが、これでyamlの説明は終了です。

仮想化ソフトにlimaを選択した背景

「最初に」にもどる

 新人研修ではどんな技術職場に配属されても仕事ができるように、いろんな研修をしています。といっても配属先ではそこの仕事に応じた技術が使われていますので、その部署の技術スタックに応じた研修も行われています。このため新人研修では基礎的なところを幅広くやっています。
 その一つにLinux実習があります。これまではwindowsパソコンでVirtualBoxを使ってAlmaLinuxを起動して実習をしていました。今回このwindowsパソコンをMacに変えることになりました。MacでそのままVirtual Boxや別の仮想化ソフトのutmでも良かったのですが、docker研修でlimaを使います。そこでlimaでAlmaLinuxを起動することにしたのでした。

 そもそもlimaって何なのでしょう。
 GitHubの https://github.com/lima-vm/lima のREADMEによると、本当かどうか分かりませんが、お名前はLInux virtual MAchinesからきているようです。他にこんなことも書かれています。

nerdctl(contaiNERD ctl)を含むcontainerdを Macユーザーに普及させることを目指しています。その後、プロジェクトの範囲は拡大され、他のコンテナやコンテナ以外のアプリケーションもサポートするようになりました。LimaはmacOS以外のホスト(Linux、NetBSDなど)もサポートしています。

 containerdはコンテナを実行するためのランタイムだそうですが、理解できていないため深掘りはしません。
 limaは、macOSが持っている仮想化技術を使ってcloud-init対応のクラウドイメージを直接起動しているので軽量だそうです。cloud-initとはクラウド環境や仮想マシンで初回起動時の設定を自動化する仕組みで、クラウドイメージはいろんなLinuxディストリビューションが提供しています。「ローカルインストール時もcloud-initを活用する」の記事によると、cloud-initはそもそもAmazon EC2専用のツールだったそうです。そのためでしょうか、cloud-initの実行ログはEC2でもlimaでも同じく/var/log/cloud-init-output.logに出力されています。

【次の記事を参考にしています】
containerdとDocker:それらの関係とそれらがどのように連携するかを理解する
第561回 ローカルインストール時もcloud-initを活用する

作りたいvm(Linuxサーバー)の検討

「最初に」にもどる

 vm(Linuxサーバー)の機能を決め、それを実現するための仕様を検討しました。

実習に必要な機能

 Linux実習をするだけならlimaのtemplateでvmを起動するだけで良いのですが、複数人が参加する研修なので、みんなが同じ環境で実習したいのです。
 同じ環境とは、こんなことを考えました。

  1. みんなが同じユーザー
     vmへのログインやディレクトリーやファイルの操作を、全員が同じコマンド、同じ構文で実習をしたい。パスワードも同じにして、パスワードを忘れた人がいてもすぐに実習が再開できるようにしたい。
  2. SSHログインしたい
     実務ではサーバーにログインすることが多々あるためです。
  3. phpMyAdminを使いたい
     データベースの研修で、sqlとかtransaction処理とかの実習に使えるからです。
  4. ディレクトリー共有
     Macとvmで、ディレクトリーを共有するとscpなどを使わなくてもファイルの交換ができます。以前は共有ディレクトリーを、vmのapacheのdocument rootにして、そこを利用してphpの実習をしていました。

vm(Linuxサーバー)の性能の検討

 こんな性能を考えていましたが、念のためにCopilotにも聞いてみました。

  • 仮想CPU: 2
  • メモリー: 2GB
  • ストレージ: 8GB

 Copilotに聞いた結果は、こうでした。

  1. メモリーの目安
    • 最小構成(テスト・開発用)
    ○ 1GB〜2GB
     Apache、MariaDB、PHPを軽く動かす程度なら1GBでも可能ですが、MariaDBがメモリーを消費するので2GBあると安定します。
     WordPressや小規模CMSを動かすなら最低2GB、余裕を持たせるなら4GB。
  2. スワップ領域の目安
    Linuxの一般的な推奨値:
    • メモリーが2GB以下の場合 → スワップはメモリーの2倍(例:RAM 1GB → SWAP 2GB)
    • メモリーが2GB〜8GBの場合 → スワップはメモリーと同程度(例:RAM 4GB → SWAP 4GB)
    • メモリーが8GB以上の場合 → スワップは2GB〜4GB程度でOK
  3. Limaでの注意点
    • LimaはmacOS上で動く仮想環境なので、ホスト側のメモリーを圧迫しないようにすることが重要です。
    • macOSのメモリーが16GBなら、AlmaLinuxには2GB〜4GB程度を割り当てるのが現実的。
  4. ディスク
    • MariaDBやログを考慮して10GB以上。

 こうして、Linuxサーバー仕様(仮想マシン構成)を決めました。

template調査

「最初に」にもどる
 目的の仕様にするには、どんなyamlファイルにすれば良いか分からないので、まずはAlmaLinuxのtemplateを使ってvmを起動して、状況を調べました。

templateの選択

 limaでは目的とするvmに応じたtemplateが準備されています。
 今回はAlmaLinuxを使いたいので、どんなtemplateがあるのか調べます。
 limactl start --list-templatesでtemplateを表示してくれます。

akita@XXXXXXXXXX ~ % limactl start --list-templates | grep alma
almalinux
almalinux-10
almalinux-8
almalinux-9
almalinux-kitten
almalinux-kitten-10

 実体は、/opt/homebrew/Cellar/lima/2.0.1/share/lima/templates/かな。
 almalinux-10を使うことにしました。

いよいよvmの起動と観察

 起動するコマンドはこれです。
limactl start template://[template name] --name=[instance name]

 今回は、[template name]はalmalinux-10、[instance name]をalma10にします。
limactl start template://almalinux-10 --name=alma10

 起動していろいろ調べました。

# vmの作成と起動
akita@XXXXXXXXXX ~ % limactl start template://almalinux-10 --name=alma10
? Creating an instance "alma10" Proceed with the current configuration
WARN[0001] field `mounts[1].location` refers to a non-existent directory: "/tmp/lima": 
INFO[0001] Starting the instance "alma10" with VM driver "vz" 
      **中略**
INFO[0070] [hostagent] The final requirement 1 of 1 is satisfied 
INFO[0070] READY. Run `limactl shell alma10` to open the shell. 
akita@XXXXXXXXXX ~ % 

# できあがったvmを確認
akita@XXXXXXXXXX ~ % limactl ls          
NAME             STATUS     SSH                CPUS    MEMORY    DISK      DIR
alma10           Running    127.0.0.1:64391    4       4GiB      100GiB    ~/.lima/alma10

# ログインしてみる
akita@XXXXXXXXXX ~ % limactl shell alma10

# ログイン後は、ホームディレクトリーじゃないのね。
[akita@lima-alma10 akita]$ pwd
/Users/akita
[akita@lima-alma10 akita]$ echo $HOME
/home/akita.linux

# ここはMacのホームディレクトリーと共有しているのね。
[akita@lima-alma10 akita]$ ls /Users/akita/
 Downloads          Movies           Music           Library
       **中略**
 Desktop          Pictures                         Documents        Public

# なんか書き込みができそうで、できない。
[akita@lima-alma10 akita]$ whoami
akita
[akita@lima-alma10 akita]$ ls -l /Users
total 0
drwxr-x---. 39 akita akita 1248 Nov  7 16:06 akita
[akita@lima-alma10 akita]$ touch /Users/akita/dummy.txt
touch: cannot touch '/Users/akita/dummy.txt': Read-only file system
[akita@lima-alma10 akita]$ 

#ストレージは/dev/vda3 に100GB、mount何ちゃらはMacのホームディレクトリーかな?
[akita@lima-alma10 akita]$ df -m
Filesystem     1M-blocks   Used Available Use% Mounted on
/dev/vda3         101111   3385     97727   4% /
       **中略**     
mount0            471483 140508    330975  30% /Users/akita
mount1            471483 140508    330975  30% /tmp/lima
       **中略**     
[akita@lima-alma10 akita]$ 

#swap領域は無いのね
[akita@lima-alma10 akita]$ free
               total        used        free      shared  buff/cache   available
Mem:         3996168      416724     2352664       17016     1391496     3579444
Swap:              0           0           0

# あらSSHのポートがぽっかり口を開けている
[akita@lima-alma10 akita]$ ss -antl
[akita@lima-alma10 akita]$ ss -antpl
State     Recv-Q    Send-Q       Local Address:Port        Peer Address:Port    Process                                                                         
LISTEN    0         4096               0.0.0.0:111              0.0.0.0:*                                                                                       
LISTEN    0         128                0.0.0.0:22               0.0.0.0:*                                                                                       
LISTEN    0         4096             127.0.0.1:40649            0.0.0.0:*        users:(("containerd",pid=1185,fd=12))                                          
LISTEN    0         4096                  [::]:111   ssh              [::]:*                                                                                       
LISTEN    0         128                   [::]:22                  [::]:*                               

# sshdは22をlistenしている
[root@lima-alma10 ~]# sudo grep Port /etc/ssh/sshd_config
#Port 22
#GatewayPorts no
[root@lima-alma10 ~]# ss -tnlp | grep sshd
LISTEN 0      128          0.0.0.0:22         0.0.0.0:*    users:(("sshd",pid=1110,fd=7))                           
LISTEN 0      128             [::]:22            [::]:*    users:(("sshd",pid=1110,fd=8))       
[akita@lima-alma10 akita]$ exit
logout

# SSHログイン。ちゃんとホームディレクトリーに入る
akita@XXXXXXXXXX ~ % ssh -p 64391 -i ~/.lima/_config/user akita@localhost

Last login: Mon Nov 10 12:11:48 2025 from 192.168.5.2
[akita@lima-alma10 ~]$ pwd
/home/akita.linux
[akita@lima-alma10 ~]$ exit
logout

# 止めます
akita@XXXXXXXXXX ~ % limactl stop alma10 
INFO[0000] Sending SIGINT to hostagent process 32976    
       **中略**     
INFO[0002] The instance alma10 has shut down            

# 消します。
akita@XXXXXXXXXX ~ % limactl delete alma10
INFO[0000] The vz driver process seems already stopped
         **中略**
INFO[0000] Deleted "alma10" ("/Users/akita/.lima/alma10") 
akita@XXXXXXXXXX ~ % 

 ちなみにこの時のMac。22ポートは開いていません。その代わり64391でSSHをlistenしています。それらのポートはlocalhostにバインドしていますので、このMacからしか接続できません。

# Macはいっぱい口を開けているけど、127.0.0.1(localhost)にバインドしている
akita@XXXXXXXXXX ~ % lsof -nP -iTCP -sTCP:LISTEN | awk '{print $1, $9, $10}'
COMMAND NAME 
limactl 127.0.0.1:64392 (LISTEN)
limactl *:111 (LISTEN)
limactl 127.0.0.1:40649 (LISTEN)
limactl 127.0.0.1:64391 (LISTEN)
limactl *:111 (LISTEN)

# listenしているポートがいくつかあるが、limactl lsで見えているポートでしかログインできない
akita@XXXXXXXXXX ~ % limactl ls                                          
NAME             STATUS     SSH                CPUS    MEMORY    DISK      DIR
alma10           Running    127.0.0.1:64391    4       4GiB      100GiB    ~/.lima/alma10
akita@XXXXXXXXXX ~ % 

# ログインできない
akita@XXXXXXXXXX ~ % ssh -p 40649 -i ~/.lima/_config/user akita@localhost
Connection closed by 127.0.0.1 port 40649

# ログインできない
akita@XXXXXXXXXX ~ % ssh -p 64392 -i ~/.lima/_config/user akita@localhost
Connection closed by 127.0.0.1 port 64392

# ログインできた
akita@XXXXXXXXXX ~ % ssh -p 64391 -i ~/.lima/_config/user akita@localhost
Last login: Mon Nov 10 14:00:46 2025 from 192.168.5.2
[akita@lima-alma10 ~]$ 

他のパソコンからアタック。当然、答えてくれません。

# 繋がっている
PS C:\Users\akita> ping jjj.kkk.mmm.nnn
jjj.kkk.mmm.nnn に ping を送信しています 32 バイトのデータ:
jjj.kkk.mmm.nnn からの応答: バイト数 =32 時間 =16ms TTL=61
jjj.kkk.mmm.nnn からの応答: バイト数 =32 時間 =21ms TTL=61
jjj.kkk.mmm.nnn からの応答: バイト数 =32 時間 =119ms TTL=61
jjj.kkk.mmm.nnn からの応答: バイト数 =32 時間 =25ms TTL=61

# でも接続できない
PS C:\Users\akita> ssh akita@jjj.kkk.mmm.nnn
ssh: connect to host jjj.kkk.mmm.nnn port 22: Connection refused
PS C:\Users\akita> ssh -p 40649 akita@jjj.kkk.mmm.nnn
ssh: connect to host jjj.kkk.mmm.nnn port 40649: Connection refused
PS C:\Users\akita> ssh -p 64391 akita@jjj.kkk.mmm.nnn
ssh: connect to host jjj.kkk.mmm.nnn port 64391: Connection refused
PS C:\Users\akita> ssh -p 64392 akita@jjj.kkk.mmm.nnn
ssh: connect to host jjj.kkk.mmm.nnn port 64392: Connection refused
PS C:\Users\akita>

観察をして分かったこと

○limactl lsから

  • SSH:127.0.0.1:64391 ローカルホスト(Mac)からのみ64391ポートで待ち受け
  • CPUS:4つ
  • MEMORY:4GiB
  • DISK:100GiB
  • DIR:このvmに関するファイルが保存されているMacのディレクトリー

○ログインして分かったこと

  • limactl shellコマンドでログインすると、ユーザーはMacユーザーと同じ。vmのログイン先ディレクトリーは、ユーザーのホームディレクトリーではなく、Macのホームディレクトリーと同じ名前
  • SSHコマンドでログインはできるけど、毎回tcpポート番号が変わる
  • SSHコマンドでのログインは公開鍵認証方式。動作は普通のサーバーと同じ
  • Macのホームディレクトリーがマウントされている。でも書き込み不可
  • swap領域はない
  • 22ポート、111ポートが思いっきり口を開けている
  • 22ポートを含めてSSHのポートは、限られたポートしかconnectionをもてない。111は調べていません
  • sshdは22でlistenしているけど、内部的に?40649にマッピング?して、Macに対しては64391にforwardしているようす

観察結果から考察

これだけでも、目指すLinux環境とかけ離れています。

  • SSHのポートは2222に固定したい
  • cpuは2つにしたい
  • memoryは2GBにしたい
  • DISKは8GBにしたい
  • みんなのvmでroot以外の同じuserIDにしたい

 考察の結果、先に決めたLinuxサーバー仕様のvmを作るためのyaml作成を目指しました。

limaの主なコマンド

「最初に」にもどる

 limaの操作については、webサイトをたくさん参考にしました。msのCopilotにも聞きました。その結果、limactlコマンドでいろんなことができるようです。

操作 コマンド例 説明
作成 limactl create [yaml file] [instance name] VMを作成
起動 limactl start [instance name] VMを起動(イメージが無ければ作成)
停止 limactl stop [instance name] VMを停止
強制停止 limactl stop -f [instance name] VMを強制的に停止
削除 limactl delete [instance name] VMを削除
状態表示 limactl ls または limactl list VMの一覧と状態を表示
SSHログイン limactl shell [instance name] VMにSSHでログイン

 createでもstartでもvmを作ることができるので、2つの違いを知りたくってweb検索をしましたが、なんだかわからないのでCopilotさんに聞きました。

初回の limactl start(インスタンス未作成)
→ インスタンス作成+初期化+プロビジョニングをまとめて実行します。
具体的には イメージ取得、ディスク作成、SSH鍵設定、マウント設定、cloud-initによるプロビジョニングスクリプト実行などが含まれます。
このため、初回は時間がかかります。

2回目以降の limactl start(インスタンス作成済み)
→ 既存VMの起動のみ。ディスクや設定はそのまま利用し、「初回のみ」指定のプロビジョニングは再実行されません(毎回実行したい場合は mode: always を設定)。

【次の記事を参考にしています】
lima Docs:start
lima github

githubの方は分かりにくいです。

最後に

「最初に」にもどる

 初めてlimaを使いました。yamlファイルにいろんな設定をしました。作るときにはlimaのことをwebでいっぱい検索しましたが、基本の設定とdocker desktop代替以外の情報はあまり見つかりませんでした。そのためCursorやCopilotにいっぱい考えてもらいました。でもあらためて考えると、情報が少ないという事は需要がないということなのでしょう。
 でも、いろいろ勉強になったから良いか。

6
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?