のぴぴのメモ

自分用のLinuxとかの技術メモ

freeコマンドとmeminfoを取得してCSV形式で保存するシェルスクリプト

はじめに

昔作った/proc/meminfoを取得時刻情報取得スクリプトを改造して作った、freeコマンド+/proc/meminfoを取得して、CSV形式で出力するシェルスクリプトです。
nopipi.hatenablog.com

ツール説明

使い方

  1. シェルのファイルを配置して、"chmod +x collect_mem.sh"で実行権限を付与する。
  2. 実行する。(カレントディレクトリに、"meminfo.YYYYMMDDHHMMSS"形式で3秒間隔でデータが出力されます)
  3. 終了したい場合は、”Ctrl+c”で終了する。

出力結果

CSV形式で以下の情報がファイルに出力されます。

  • 取得日と時刻
  • freeコマンド 2行目(Mem:)の各情報
  • freeコマンド 3行目(Swap:)の各情報
  • /proc/meminfo情報
"DATE","TIME","free-mem-total(kb)","free-mem-used(kb)","free-mem-free(kb)","free-mem-share(kb)","free-mem-buff/cache(kb)","available(kb)","free-swap-total(kb)","free-swap-used(kb)","free-swap-free(kb)","MemTotal:(kB)","MemFree:(kB)","MemAvailable:(kB)","Buffers:(kB)","Cached:(kB)","SwapCached:(kB)","Active:(kB)","Inactive:(kB)","Active(anon):(kB)","Inactive(anon):(kB)","Active(file):(kB)","Inactive(file):(kB)","Unevictable:(kB)","Mlocked:(kB)","SwapTotal:(kB)","SwapFree:(kB)","Dirty:(kB)","Writeback:(kB)","AnonPages:(kB)","Mapped:(kB)","Shmem:(kB)","Slab:(kB)","SReclaimable:(kB)","SUnreclaim:(kB)","KernelStack:(kB)","PageTables:(kB)","NFS_Unstable:(kB)","Bounce:(kB)","WritebackTmp:(kB)","CommitLimit:(kB)","Committed_AS:(kB)","VmallocTotal:(kB)","VmallocUsed:(kB)","VmallocChunk:(kB)","HardwareCorrupted:(kB)","AnonHugePages:(kB)","HugePages_Total:()","HugePages_Free:()","HugePages_Rsvd:()","HugePages_Surp:()","Hugepagesize:(kB)","DirectMap4k:(kB)","DirectMap2M:(kB)"
2017/09/27, 03:46:11,1883560,386348,792416,70516,704796,1237452,839676,0,839676,1883560,792680,1237716,5652,618276,0,313016,390848,80848,69604,232168,321244,0,0,839676,839676,0,0,79948,23984,70516,80868,45604,35264,1744,4952,0,0,0,1650384,365624,34359738367,7444,34359728128,0,6144,128,128,0,0,2048,44992,2052096
2017/09/27, 03:46:14,1883560,386144,792616,70516,704800,1237656,839676,0,839676,1883560,792680,1237720,5652,618280,0,313044,390848,80872,69604,232172,321244,0,0,839676,839676,4,0,79956,23984,70516,80868,45604,35264,1808,4924,0,0,0,1650384,365624,34359738367,7444,34359728128,0,6144,128,128,0,0,2048,44992,2052096

*補足
HugePage周りの挙動を確認するための情報収集用にこしらえたものです。

"LB + Web x 2 + RDB"マルチAZ”でWordPressをインストールするCloudFormation

はじめに

前にAWSさんの体験ハンズオンで経験した"LB + Web x 2 + DB x 2"環境構築して、そこに動作確認としてWordPressをインストールして動かすところまでの手順を、CloudFormationを使って自動化して見ました。WordPressのインストールは、CloudFormationのcfn-init ヘルパースクリプトを使っています。

構成概要

f:id:nopipi:20170910213131p:plain

  • 東京リージョンでの利用前提(手抜きです)
  • Webサーバ用のPublicSubnetを2つと、RDB用のPrivateSubnetを2つ作成
  • Subnetは2つのAZ(AvailabilityZone)にサブネットをそれぞれ配備する
  • WebサーバへのWordPressインストールは、cfn-init ヘルパースクリプトを利用。下記作業時実施。
    • 前提パッケージと、WordPressのダウンロードと解凍コピー
    • 定義ファイルの作成
    • サービスの起動

CloudFormationコード

SRPM展開&Gun global解析&squashfs化する自作ツールの説明

1.ツールができること

"srpm2html.py"は、SRPMソースコードを展開、Gnu global処理、その他諸々を自動化する自作ツールです。
具体的には、このツールを使うと以下の一連の作業をサボることができます。

コードはgithub(gist)に登録してあります。

2.インストール方法

2.1 前提環境

Linuxであれば多分動くと思います。(私は、CentOS6,AmazonLinux上で利用しています)

2.2 前提パッケージ

この自作ツールを実行するためには以下のrpmパッケージが必要です。*1*2

下記コマンドでRPMパッケージをインストールします。

sudo yum install rpm-build squashfs-tools gcc make ncurses-devel

2.3 Gnu Globalのインストー

Gnu globalはソースコードをダウンロードしてmakeします。

wget http://tamacom.com/global/global-6.5.6.tar.gz
tar -xxvf global-6.5.6.tar.gz
cd global-6.5.6
./configure
make
sudo make install

2.4 ツールのセットアップ

srpm2html.pyは、githubに登録してあるのでそこからダウンロードします。

cd "セットアップしたいディレクトリパスを指定"
wget https://gist.githubusercontent.com/Noppy/027ea703dd7084be0c3d4d99ce618109/raw/1e3eefeb83c7542d37c8c455701a0f727df128d4/srpm2html.py
chmod +x srpm2html.py 

2.5 ディレクトリの準備

デフォルトでは下記ディレクトリが必要になります。ディレクトリは実行時の引数(後述)または、pythonの先頭のデフォルト設定を書き換えることで変更可能です。

  • 必要なディレクト
    1. /tmp : srpmのダウンロードと追加するfstabの作成に使用。容量は利用しない。
    2. /data/rpmbuild : srpmインストール、コード展開、globl解析をするメイン作業用。
      • 大量のファイルを作成するため、ファイルシステムフォーマット時にするinodeを潤沢に確保したほうが良い
        • フォーマット例:mkfs.ext4 -L rpmbuild -i 2048 /dev/sdb1
      • メモリが潤沢にある場合は、tmpfs(メモリファイルシステム)の利用が良い。
    3. /data/squshfs : 作成したsquashfsファイルの格納先
    4. /data/kernel : Globalが生成したhtmlのsquashfs化したもののマウントポイントを作成するディレクトリ(kernelのsrpmを解析した場合)
    5. /data/tools : 上記と同じ(kernel以外の、srpmを解析した場合)
    6. /data/source:ソースコードsquashfs化したもののマウントポイントを作成するディレクト

2.6 sudo設定

最後のfstab更新とマウント実行時に、sudoコマンドを利用しています。srpm2html.py実行ユーザがsudoでroot昇格できるように設定を事前にして下さい。またパスワード入力が面倒な方は、NOPASSWDもして下さい。

3.使い方

3.1 簡単な使い方

簡単な使い方は以下のとおりです。

./srpm2html.py "SRPMファイルのURL"

例えば、CentOS7.3のカーネルソースを展開したい場合は以下の通りになります。

srpm2html.py http://vault.centos.org/7.3.1611/os/Source/SPackages/kernel-3.10.0-514.el7.src.rpm

3.2 引数の説明

  • 構文
usage: srpm_to_html.py [-h] [-d] [-t TMPDIR] [-r RPMBUILDDIR] [-s SQUASHFSDIR]  
                       [-K HTTP_KERNELSDIR] [-T HTTP_TOOLSDIR] [-S SOURCEDIR]  
                       SRPM_FilePath_or_URL
  • 必須引数
    • SRPM_FilePath_or_URL: srpmのURLまたは、ローカルに格納しているsrpmのファイルパスを指定します。
  • 主なオプション詳細
    • -h, --help : ヘルプの表示
    • -t TMPDIR, --tmpdir TMPDIR : tmpディレクトリの指定
    • -r RPMBUILDDIR, --rpmbuilddir RPMBUILDDIR : srpmの展開先と作業用ディレクトリの指定
    • -s SQUASHFSDIR, --squashfsdir SQUASHFSDIR : squashfsファイルの格納先ディレクトリ指定
    • -K HTTP_KERNELSDIR, --http_kernelsdir HTTP_KERNELSDIR : マウントポイントを作成するディレクトリ指定(kernel)
    • -T HTTP_TOOLSDIR, --http_toolsdir HTTP_TOOLSDIR : マウントポイントを作成するディレクトリ指定(kernel以外)
    • -S SOURCEDIR, --sourcedir SOURCEDIR : マウントポイントを作成するディレクトリ指定(ソースコード)

*1:gcc,make,ncurses-develは、Gnu globalインストール時に必要

*2:pythonも必要ですが、標準で大抵インストールされているので割愛

SRPMインストール先を指定する方法

ソースコードをパッケージ化したSRPM(拡張子がsrc.rpmのファイル)のインストール先は、デフォルトでは"${HOME}/rpmbuild"になります。(CentOS5/RHEL5以前は"/usr/src/redhat")。このデフォルトのインストール先を変更する方法を説明します。

1.普通にSRPMをインストールした場合

SRPMrpmコマンドでインストールします。

$rpm -ivh lsof-4.87-4.el7.src.rpm 

デフォルトでインストールした場合は、ホームディレクトリ配下のrpmbuildディレクトリにインストールされます。

/home/n/rpmbuild/
├── SOURCES
│   ├── lsof_4.87-rh.tar.xz
│   └── upstream2downstream.sh
└── SPECS
    └── lsof.spec

2.インストールディレクトリを指定する方法

2.1 RPMのマクロ定義ファイル("~/.rpmmacros")で指定

ネットを調べるとたいてい出てくる方法はこちらの方法になります。rpmコマンドでのSRPMインストールと、その後のrpmbuildコマンドによるビルド操作で都度、引数でディレクトリを指定する手間を考えると、マクロ定義ファイルで予め定義するほうが現実的な気はします。

(1)マクロ定義ファイルの設定

インストール先のトップディレクトリは、"%_topdir"変数になるので、この変数をマクロ定義ファイルで変更します。

$echo "%_topdir /data/rpmbuild" > ~/.rpmmacros
(2)SRPMのインストール
$rpm -ivh lsof-4.87-4.el7.src.rpm 

2.2 コマンド引数でインストールディレクトリを指定する方法

ホームディレクトリに".rpmmacros"ファイルを作成したくない場合や、一時的にインストールディレクトリを変更したい場合は、"--define="引数でマクロの変数を変更します。

$rpm -ivh --define='%_topdir /data/rpmbuild' lsof-4.87-4.el7.src.rpm

cloudformation VPC(PubSub x 2, PrivateSub x 2) + 1 Instance(t2.micro, AmazonLinux) を作るテンプレート

概要

自分用のメモです。"一つ前の記事"VPCのPublicASubにインスタンスを一つ追加したテンプレートです。

作成されるもの

  • VPC × 1
  • サブネット × 4
    • PubASub CIDR:10.0.1.0/24, AZ: ap-northeast-1a ルートテーブル: インターネットへのルーティングあり
    • PubBSub CIDR:10.0.2.0/24, AZ: ap-northeast-1c ルートテーブル: インターネットへのルーティングあり
    • PrivateASub CIDR:10.0.11.0/24, AZ: ap-northeast-1a
    • PrivateBSub CIDR:10.0.12.0/24, AZ: ap-northeast-1c
  • セキュリティグループ × 2
    • WebSecurityGroup: HTTP(port80),HTTPS(port443)を全て許可
    • SSHSecurityGroup: SSH(port22)を全て許可
  • インスタンス × 1
    • 利用イメージ: AmazonLinux("ami-56d4ad31")
    • インスタンスタイプ : t2.micro
    • サブネット: PubASub(インターネット接続あり)
    • SSHキーペア: "xxxxxxxxxxxxx"となっているので適切に修正
    • 追加EBS:
      • タイプ: デフォルトの「汎用 SSD (gp2)」
      • サイズ:20GiB
      • バイス名:/dev/xvdb

※AZは東京の場合

構成概要

f:id:nopipi:20170212222757p:plain

テンプレート

cloudformation VPC(2つのパブリックsub+2つのプライベートsub)を作るテンプレート

概要

自分用のメモです。下記のようなvpcを作るテンプレートです。

作成されるもの

  • VPC × 1
  • サブネット × 4
    • PubASub CIDR:10.0.1.0/24, AZ: ap-northeast-1a ルートテーブル: インターネットへのルーティングあり
    • PubBSub CIDR:10.0.2.0/24, AZ: ap-northeast-1c ルートテーブル: インターネットへのルーティングあり
    • PrivateASub CIDR:10.0.11.0/24, AZ: ap-northeast-1a
    • PrivateBSub CIDR:10.0.12.0/24, AZ: ap-northeast-1c
  • セキュリティグループ × 2
    • WebSecurityGroup: HTTP(port80),HTTPS(port443)を全て許可
    • SSHSecurityGroup: SSH(port22)を全て許可

※AZは東京の場合

構成概要

f:id:nopipi:20170211175348p:plain

テンプレート

ubuntuで古いカーネルを削除する方法(/bootの空きが足りない時とか)

1.はじめに

ubuntuで「ソフトウェアの更新」で「/bootのディスク容量が足りない」と言われてしまった時の対処方法です。
ubuntuが結構頻繁にkernelの更新を行うようで、私は半年ぐらい周期で/bootが足りなくなります。

f:id:nopipi:20170210112308p:plain

2.対処方法(古いkernelの削除)

(1)現在のカーネルバージョンの確認

$ uname -r
4.4.0-59-generic

(2)インストール済みカーネルのバージョン一覧を確認

現在利用中のカーネルバージョン(4.4.0-59)以外のバージョン(4.4.0-38、4.4.0-45、4.4.0-47、4.4.0-51、の4つ)をこれから削除します。

$ dpkg --get-selections |grep linux-
linux-base					install
linux-cloud-tools-4.4.0-38			install
linux-cloud-tools-4.4.0-38-generic		install
linux-cloud-tools-4.4.0-45			install
linux-cloud-tools-4.4.0-45-generic		install
linux-cloud-tools-4.4.0-47			install
linux-cloud-tools-4.4.0-47-generic		install
linux-cloud-tools-4.4.0-51			install
linux-cloud-tools-4.4.0-51-generic		install
linux-cloud-tools-common			install
linux-cloud-tools-generic			install
linux-firmware					install
linux-generic					install
linux-headers-4.4.0-36				install
linux-headers-4.4.0-36-generic			install
linux-headers-4.4.0-38				install
linux-headers-4.4.0-38-generic			install
linux-headers-4.4.0-45				install
linux-headers-4.4.0-45-generic			install
linux-headers-4.4.0-47				install
linux-headers-4.4.0-47-generic			install
linux-headers-4.4.0-51				install
linux-headers-4.4.0-51-generic			install
linux-headers-4.4.0-59				install
linux-headers-4.4.0-59-generic			install
linux-headers-generic				install
linux-image-4.4.0-36-generic			install
linux-image-4.4.0-38-generic			install
linux-image-4.4.0-45-generic			install
linux-image-4.4.0-47-generic			install
linux-image-4.4.0-51-generic			install
linux-image-4.4.0-59-generic			install
linux-image-extra-4.4.0-36-generic		install
linux-image-extra-4.4.0-38-generic		install
linux-image-extra-4.4.0-45-generic		install
linux-image-extra-4.4.0-47-generic		install
linux-image-extra-4.4.0-51-generic		install
linux-image-extra-4.4.0-59-generic		install
以下略

(3)コマンドをテスト実行確認(DryーRun)

apt-getコマンドで古いカーネルパッケージを削除します。
”--purge”オプションで削除するパッケージを指定しますが、指定が正しいか確認するため”--dry-run”オプションで空実行させて確認します。

$ sudo apt-get --dry-run autoremove --purge linux-{headers,image}-4.4.0-{36,38,45,47,51}
パッケージリストを読み込んでいます... 完了
依存関係ツリーを作成しています                
状態情報を読み取っています... 完了
<省略>
アップグレード: 0 個、新規インストール: 0 個、削除: 39 個、保留: 234 個。
Purg linux-cloud-tools-4.4.0-38-generic [4.4.0-38.57]
Purg linux-cloud-tools-4.4.0-38 [4.4.0-38.57]
Purg linux-cloud-tools-4.4.0-45-generic [4.4.0-45.66]
Purg linux-cloud-tools-4.4.0-45 [4.4.0-45.66]
Purg linux-cloud-tools-4.4.0-47-generic [4.4.0-47.68]
Purg linux-cloud-tools-4.4.0-47 [4.4.0-47.68]
Purg linux-headers-4.4.0-36-generic [4.4.0-36.55]
Purg linux-headers-4.4.0-36 [4.4.0-36.55]
Purg linux-headers-4.4.0-38-generic [4.4.0-38.57]
Purg linux-headers-4.4.0-38 [4.4.0-38.57]
Purg linux-headers-4.4.0-45-generic [4.4.0-45.66]
Purg linux-headers-4.4.0-45 [4.4.0-45.66]
Purg linux-headers-4.4.0-47-generic [4.4.0-47.68]
Purg linux-headers-4.4.0-47 [4.4.0-47.68]
Purg linux-headers-4.4.0-51-generic [4.4.0-51.72]
Purg linux-headers-4.4.0-51 [4.4.0-51.72]
Purg linux-signed-image-4.4.0-36-generic [4.4.0-36.55]
Purg linux-image-extra-4.4.0-36-generic [4.4.0-36.55]
Purg linux-image-4.4.0-36-generic [4.4.0-36.55]
Purg linux-signed-image-4.4.0-38-generic [4.4.0-38.57]
Purg linux-image-extra-4.4.0-38-generic [4.4.0-38.57]
Purg linux-image-4.4.0-38-generic [4.4.0-38.57]
Purg linux-signed-image-4.4.0-45-generic [4.4.0-45.66]
Purg linux-image-extra-4.4.0-45-generic [4.4.0-45.66]
Purg linux-image-4.4.0-45-generic [4.4.0-45.66]
Purg linux-signed-image-4.4.0-47-generic [4.4.0-47.68]
Purg linux-image-extra-4.4.0-47-generic [4.4.0-47.68]
Purg linux-image-4.4.0-47-generic [4.4.0-47.68]
Purg linux-signed-image-4.4.0-51-generic [4.4.0-51.72]
Purg linux-image-extra-4.4.0-51-generic [4.4.0-51.72]
Purg linux-image-4.4.0-51-generic [4.4.0-51.72]
Purg linux-tools-4.4.0-36-generic [4.4.0-36.55]
Purg linux-tools-4.4.0-36 [4.4.0-36.55]
Purg linux-tools-4.4.0-38-generic [4.4.0-38.57]
Purg linux-tools-4.4.0-38 [4.4.0-38.57]
Purg linux-tools-4.4.0-45-generic [4.4.0-45.66]
Purg linux-tools-4.4.0-45 [4.4.0-45.66]
Purg linux-tools-4.4.0-47-generic [4.4.0-47.68]
Purg linux-tools-4.4.0-47 [4.4.0-47.68]

4.4.0-36,38,45,47,51の5つのバージョンが選択されていることを確認します。

(4)パッケージを削除する

”--dry-run”オプションを外して削除実行します。

$ sudo apt-get autoremove --purge linux-{headers,image}-4.4.0-{36,38,45,47,51}

(5)削除されたか確認

4.4.0-51以外のバージョンのカーネル削除されたか確認します。

$ dpkg --get-selections |grep linux-
linux-base					install
linux-cloud-tools-4.4.0-51			install
linux-cloud-tools-4.4.0-51-generic		install
linux-cloud-tools-common			install
linux-cloud-tools-generic			install
linux-firmware					install
linux-generic					install
linux-headers-4.4.0-59				install
linux-headers-4.4.0-59-generic			install
linux-headers-generic				install
linux-image-4.4.0-59-generic			install
linux-image-extra-4.4.0-59-generic		install
linux-image-extra-virtual			install
linux-image-generic				install
linux-libc-dev:amd64				install
linux-signed-generic				install
linux-signed-image-4.4.0-59-generic		install
linux-signed-image-generic			install
linux-sound-base				install
linux-tools-4.4.0-51				install
linux-tools-4.4.0-51-generic			install
linux-tools-common				install
linux-tools-generic				install
syslinux-common					install
syslinux-legacy					install

ansibleのベストプラクティスなplaybookレイアウトを作るシェル

ansibleのベストプラクティスなplaybookディスクレイアウトがあります。

このディレクトリを手動で作成するのが面倒なので簡単なシェルを作成しました。
こんなディレクトリレイアウトとmain.ymlの空ファイルを作成します。

group_vars/
host_vars/
site.yml                  # master playbook
roles/
    RoleName1/               # this hierarchy represents a "role"
        tasks/            #
            main.yml      #  <-- tasks file can include smaller files if warranted
        handlers/         #
            main.yml      #  <-- handlers file
        templates/        #  <-- files for use with the template resource
        files/            #
        vars/             #
            main.yml      #  <-- variables associated with this role
        defaults/         #
            main.yml      #  <-- default lower priority variables for this role
        meta/             #
            main.yml      #  <-- role dependencies

コードはこちら。

gitの初期設定をしてGitHubからレポジトリをcloneするまでの手順

はじめに

PCを再セットアップした後、いつも設定方法を忘れてgoogleさんに聞いて面倒なので、まとめました。

git初期設定

ユーザ設定&pushモード設定

(1)メールアドレス、(2)名前、(3)push時のモードを指定して、最後に設定内容を確認。

git config --global user.email "xxxxxxx@gmail.com"
git config --global user.name "xxxxxxxx"
git config --global push.default simple

git config --global -l

git認証情報の自動保存設定

# Linuxで認証情報を保存したい場合
git config --global credential.helper store

git Proxy設定(必要があれば)

git config --global http.proxy http://proxy.example.com:3128
git config --global https.proxy http://proxy.example.com:3128

git を使いやすくする設定

コミットログを見やすくするコマンドのエリアス

~/.gitconfigに下記を追加

[alias]
    lga = log --graph --all --pretty=format:'%C(red)%h %C(reset)-%C(yellow)%d%C(reset) %s %C(green)(%cr) %C(bold blue)<%an>%C(reset)'
    lg  = log --graph       --pretty=format:'%C(red)%h %C(reset)-%C(yellow)%d%C(reset) %s %C(green)(%cr) %C(bold blue)<%an>%C(reset)'
  • 使い方: git lga、またはgit lgと実行

SSH秘密鍵設定

githubへのssh接続を鍵認証で行う場合の設定。

  • 秘密鍵: "~/.ssh/id_rsa"に保存(※1)
  • 公開鍵:githubページから"Settings"->"SSH and GPG keys"で公開鍵を登録

※1 秘密鍵パーミッションは、".ssh/"ディレクトリは700、秘密鍵(id_rsa)ファイルは600。SSH鍵がない場合は、"ssh-keygen"コマンドで鍵を作成する。なおGitHub専用の秘密鍵にしたい場合は後述。

シェル設定

シェルのプロンプトにブランチ名を表示する

こんな感じでプロンプトにgitブランチ名を表示できるようにします。

GitHubからcloneする

(既存レポジトリがない場合)新規にレポジトリの作成

  • "New repository"からレポジトリを作成
  • 必要な項目を設定
    • レポジトリ名を指定(Repository name)
    • "Initialize this repository with a README"をチェック
    • "Add .gitignore"で開発したい言語のgitigonreテンプレを選択
    • "Add a license"で開発するブツのライセンスを指定(Apache LicenseとかGPLv3とか)
  • "Create repository"でレポジトリを作成

レポジトリをcloneする

  • GithubのページからURLをコピーする
    • cloneしたいgithubレポジトリページを開き、
    • 緑のボタン"Clone or download"のプルダウンから
    • 表示されているURLをコピーする

  • gitコマンドでcloneする
    • 格納したいディレクトリに移動し
    • "git clone <コピーしたURL>"でデータをローカルにcloneする
$ git clone https://github.com/Noppy/uplogger.git
Cloning into 'uplogger'...
remote: Counting objects: 254, done.
remote: Total 254 (delta 0), reused 0 (delta 0), pack-reused 254
Receiving objects: 100% (254/254), 382.28 KiB | 226.00 KiB/s, done.
Resolving deltas: 100% (141/141), done.
Checking connectivity... done.

(追伸)ssh秘密鍵GitHub専用ファイルに分けて指定したい時

gitコマンドでは直接sshの鍵設定ができないので、sshコマンドの設定ファイル(~/.ssh/config)を駆使したりする。他に環境変数で設定するとかもあるらしい。

vi ~/.ssh/config
Host github
    User git
    Port 22
    HostName github.com
    IdentityFile   ~/.ssh/gitub_id_rsa
    IdentitiesOnly yes

説明

  • ユーザは、"git"固定
  • ホスト名、ポート番号は、"github.com"で22番ポート
  • IdentityFileで、GitHub専用の秘密鍵ファイルのパスを指定する。
  • "IdentitiesOnly yes"で認証で利用する秘密鍵をIdentityFileで指定したファイルのみに限定する

KickStartその3(ネットワーク構成例 -vlan、bonding構成も)

0.関連記事一覧

1.はじめに

KickStarでosを自動インストールするときのネットワーク設定について、構成例をケース毎に説明します。vlan、bondや、vlanとbondを組み合わせた構成も説明します。

2.ネットワーク構成例

2.1静的IP構成

(1)構成イメージ

f:id:nopipi:20160802203126p:plain

(2)KickStart設定例

networkオプションで設定します。"--bootproto=static"とし、IPなど必要な設定を行います。

# Network information
network --bootproto=static --ip=10.0.2.15 --netmask=255.255.255.0 --gateway=10.0.2.2 --nameserver=192.168.11.1 --device=enp0s3 --noipv6 --activate
network --hostname=Server1

2.2DHCP設定の場合

(1)構成イメージ

f:id:nopipi:20160802203127p:plain

(2)KickStart設定例

networkオプションで、"--bootproto=dhcp"とします。

network --bootproto=dhcp --device=enp0s3 --noipv6 --activate
network --hostname=Server1

2.3複数セグメント設定

(1)構成イメージ

f:id:nopipi:20160802203128p:plain

(2)KickStart設定例

複数セグメントがある場合は、networkオプションを複数行記載します。

network --bootproto=dhcp --device=enp0s3 --noipv6 --activate
network --bootproto=static --device=enp0s8 --ip=192.168.0.20 --netmask=255.255.255.0 --nodefroute --nodns --noipv6 --activate
network --hostname=Server1

2.4VLAN設定

(1)構成イメージ

f:id:nopipi:20160802203129p:plain

(2)KickStart設定例

networkオプションで、"--vlanid="でVLAN IDを指定します。デバイス名を指定したい場合は、"--interfacename="を使います。未指定の場合は、"デバイス名.VLAN-ID"名称になります。

network --bootproto=dhcp --device=enp0s3 --noipv6 --activate
network --bootproto=static --device=enp0s8 --ip=192.168.0.20 --netmask=255.255.255.0 --nodefroute --nodns --noipv6 --activate
network --device=enp0s8 --vlanid=1000 --interfacename=enp0s8.1000 --bootproto=static --ip=192.168.10.20 --netmask=255.255.255.0 --nodefroute --nodns --noipv6 --activate
network --hostname=Server1

2.5bond設定(ネットワーク冗長化設定)

(1)構成イメージ

f:id:nopipi:20160802203130p:plain

(2)KickStart設定例

networkオプションでもbond構成を設定可能ですが、slaveデバイスがMacアドレス指定となるのが難点です。(LANカード交換によるmacアドレス変更後に設定変更が必要になるため)。slave指定をデバイス名(enp0s8とか)で指定するため、インストールの後処理(%post〜%endセクション)でNetworkManager(nmcliコマンド)で設定を作成し、インストールイメージにコピーする手段をとっています。post処理はNetworkManagerのデーモン経由の処理になるので、chrootを無効化して処理させます。

network --bootproto=dhcp --device=enp0s3 --noipv6 --activate
network --hostname=Server1
<中略>
%post --nochroot --log=/mnt/sysimage/root/ks-post-log.log

# delete enp0s8n and enp0s9 configuration file
nmcli c delete enp0s8
nmcli c delete enp0s9

# add a bond device
nmcli c add type bond ifname bond0 con-name bond0 mode active-backup miimon 100 updelay 600 primary enp0s8 
nmcli c mod bond0 ipv4.method manual ipv4.address "192.168.0.20/24" ipv4.never-default yes
nmcli c mod bond0 ipv6.method ignore ipv6.never-default yes
nmcli c add type bond-slave ifname enp0s8 con-name bond0-enp0s8 master bond0
nmcli c add type bond-slave ifname enp0s9 con-name bond0-enp0s9 master bond0

# copy network configurate files to the install image
rm -rf /mnt/sysimage/etc/sysconfig/network-scripts/ifcfg-*
cp -p /etc/sysconfig/network-scripts/ifcfg-* /mnt/sysimage/etc/sysconfig/network-scripts/

%end

2.6bond-vlan設定

(1)構成イメージ

f:id:nopipi:20160802203131p:plain

(2)KickStart設定例

応用です。bondデバイスを作成し、その上にVLANを設定する例です。

# Network information
network --bootproto=dhcp --device=enp0s3 --noipv6 --activate
network --hostname=Server1
<中略>
%post --nochroot --log=/mnt/sysimage/root/ks-post-log.log

# delete enp0s8n and enp0s9 configuration file
nmcli c delete enp0s8
nmcli c delete enp0s9

# add a bond device
nmcli c add type bond ifname bond0 con-name bond0 mode active-backup miimon 100 updelay 600 primary enp0s8
nmcli c mod bond0 ipv4.method disabled ipv6.method ignore
nmcli c add type bond-slave ifname enp0s8 con-name bond0-enp0s8 master bond0
nmcli c add type bond-slave ifname enp0s9 con-name bond0-enp0s9 master bond0

# add vlan devices(disable ipv4/v6 address)
nmcli c add type vlan ifname bond0.1000 con-name bond0.1000 dev bond0 id 1000
nmcli c mod bond0.1000 ipv4.method manual ipv4.address "192.168.10.20/24" ipv4.never-default yes
nmcli c mod bond0.1000 ipv6.method ignore

# copy network configurate files to the install image
rm -rf /mnt/sysimage/etc/sysconfig/network-scripts/ifcfg-*
cp -p /etc/sysconfig/network-scripts/ifcfg-* /mnt/sysimage/etc/sysconfig/network-scripts/

%end

2.7vlan-bond設定

(1)構成イメージ

f:id:nopipi:20160802203132p:plain

(2)KickStart設定例

上記の逆で、VLANデバイスを束ねてbondデバイスを構成する例です。あまり用途はないと思いますが。

network --bootproto=dhcp --device=enp0s3 --noipv6 --activate
network --hostname=Server1
<中略>
%post --nochroot --log=/mnt/sysimage/root/ks-post-log.log

# disable ipaddress at enp0s8n and enp0s9
nmcli c mod enp0s8 ipv4.method disabled ipv6.method ignore
nmcli c mod enp0s9 ipv4.method disabled ipv6.method ignore

# add vlan devices(disable ipv4/v6 address)
nmcli c add type vlan ifname enp0s8.1000 con-name enp0s8.1000 dev enp0s8 id 1000
nmcli c add type vlan ifname enp0s9.1000 con-name enp0s9.1000 dev enp0s9 id 1000
nmcli c mod enp0s8.1000 ipv4.method disabled ipv6.method ignore
nmcli c mod enp0s9.1000 ipv4.method disabled ipv6.method ignore

# add a bond device
nmcli c add type bond ifname bond0 con-name bond0 mode active-backup miimon 100 updelay 600 primary enp0s8.1000
nmcli c mod bond0 ipv4.method manual ipv4.address "192.168.10.20/24" ipv4.never-default yes
nmcli c mod bond0 ipv6.method ignore
nmcli c add type bond-slave ifname enp0s8.1000 con-name bond0-enp0s8.1000 master bond0
nmcli c add type bond-slave ifname enp0s9.1000 con-name bond0-enp0s9.1000 master bond0
nmcli c mod enp0s8.1000 connection.master bond0 connection.slave-type bond
nmcli c mod enp0s9.1000 connection.master bond0 connection.slave-type bond

# copy network configurate files to the install image
rm -rf /mnt/sysimage/etc/sysconfig/network-scripts/ifcfg-*
cp -p /etc/sysconfig/network-scripts/ifcfg-* /mnt/sysimage/etc/sysconfig/network-scripts/

%end

KickStartその2(ks.cfg設定ファイルの説明)

0.関連記事一覧

1.はじめに

この記事は、RHEL/fedoraのOS自動インストールを行うKickStartの設定ファイル(ks.cfg)の書き方の詳細です。ネットワーク設定、ディスク設定、パッケージ設定、ユーザ設定、を中心に編集頻度が高そうな項目を説明します。

2.ネットワーク設定

(1)スタティック設定例

enp0s3,enp0s8双方をstaticでネットワーク設定する場合の例です。

# Network information
network --bootproto=static --device=enp0s3 --ip=10.0.2.15    --netmask=255.255.255.0 --gateway=10.0.2.2 --nameserver=10.0.2.3  --noipv6 --activate
network --bootproto=static --device=enp0s8 --ip=192.168.0.20 --netmask=255.255.255.0 --noipv6 --activate --nodefroute 
network --hostname=testserve
  • "--bootproto=static"とすることで、静的設定になります。
  • "--device"で、設定するデバイスを指定します。
  • "--ip"、"--netmask="、"--gateway="でIP設定をします。
  • "--nameserver"で、参照先DNSを指定します。DNSが複数ある場合は、"=x.x.x.x,y.y.y.y"とカンマで区切って指定します。
  • "--noipv6"で、ipv6を無効化します。
  • "--activate"を付けることで、boot時にデバイスが有効化されます。
  • "--nodefroute "は、デフォルトGWと通信しないデバイスに設定します。
  • "network --hostname=xxxx"で、ホスト名を設定します。

(2)DHCP設定例

enp0s3をDHCP設定に変更した例です。

# Network information
network --bootproto=dhcp   --device=enp0s3 --noipv6 --activate
network --bootproto=static --device=enp0s8 --ip=192.168.0.20 --netmask=255.255.255.0 --noipv6 --activate --nodefroute 
network --hostname=testserver
  • "--bootproto=dhcp"とすることでDHCP設定となります。
  • ほかは(1)の内容と同じです。

bonding・vlanと組み合わせた構成は下記記事を参照して下さい。
nopipi.hatenablog.com

3.ディスク設定

インストール時のディスク構成(パーティション、LVM、ファイルシステムなど)を指定します。ディスク設定は、設計したディスク構成になるよう手動で組み直したほうが基本良さそうです。

(1)ブートディスク構成例*1

f:id:nopipi:20160719100545p:plain

(2)上記構成例の場合のKickStart設定
# Specifies used disk for installation 
ignoredisk --only-use=sda

# System bootloader configuration
bootloader --append=" crashkernel=auto" --location=mbr --boot-drive=sda

# Partition clearing information
clearpart --all --initlabel --drives sda

# Disk partitioning information
part pv.295 --fstype="lvmpv" --ondisk=sda --size=1    --grow
part /boot  --fstype="xfs"   --ondisk=sda --size=500  --label=boot
volgroup rootvg --pesize=4096 pv.295
logvol swap  --fstype="swap" --size=256        --name=swaplv --vgname=rootvg
logvol /home --fstype="xfs"  --size=100        --name=homelv --vgname=rootvg --label="home" 
logvol /     --fstype="xfs"  --size=1   --grow --name=rootlv --vgname=rootvg --label="root" 
  1. インストーラが対象とするディスクの指定
    1. "ignoredisk"で"--only-use="オプションを設定すると、指定したディスクのみインストーラの対象になります。
  2. ブートローダの指定
    1. anaconda-ks.cfgから基本編集しませんが、"bootloader"で"--location=mbr"とすることで、MBRブートローダがインストールされます。
  3. ディスクフォーマット(既存パーティション削除)
    1. "clearpart --all --initlabel --device sda"で対象ディスクの既存パーティションを全て削除します。*2
  4. パーティション設定
    1. partコマンドでパーティションを作成します。
    2. パーティション用途指定
      1. ファイルシステムとして利用: "part /boot --fstype="xfs" "と記載します。
      2. スワップとして利用: "part swap --fstype="swap" "と記載します。
      3. LVMとして利用: "part pv.XX --lvmpv" "と記載します。XXは識別番号で任意の数字です。
    3. サイズ指定
      1. 固定サイズ指定:"--size xxx"と記載。xxxはMB単位でサイズ指定します。
      2. 残り容量全て:"--grow"オプションを利用し、"--size 1 --grow"のように記載します。この場合、最低容量1MBで空きがあるだけ確保する設定になります。
    4. その他
      1. "--ondisk="で、パーティションを作成するディスクを指定します。
      2. ファイルシステムにラベル名を指定するときは、"--label=xxxx"で設定します。
  5. LVM
    1. vg作成: "volgroup VG名 --pesize=4096 PVのパーティション"で作成します。
      1. "--pesize":任意のオプションです。LVMのPEサイズをKiBで指定します。
    2. LV作成: "logvol --name=LV名称 --vgname=VG名"で作成します。ファイルシステム、サイズ指定など、他のパラメータはpartコマンドと同じです。
      1. "--name=XXX":作成するLV名称を指定します。
      2. "--vgname=XXX":LVを作成するVGを指定します。

4.インストールパッケージ設定

インストルするパッケージは、下記のように"%packages 〜 %end"のセクションの間で設定します。基本はGUIで設定内容に足りないパッケージを追加するのが簡単です。

%packages
@^infrastructure-server-environment
@base
@compat-libraries
@core
@large-systems
@performance
@security-tools
kexec-tools
telnet
trace-cmd
vim
%end
  1. @で始まるのがインストールするパッケージグループです。
  2. 足りないパッケージを個別に追加します。

5.ユーザ設定

(1)rootユーザのパスワード設定

rootユーザのパスワードは"rootpw"で設定します。パスワードは、(a)平文文字列、または(b)暗号化された文字列で指定できます。

(1)-(a)パスワードを平文で記載する場合

オプション無し、または"--plaintext"オプションを付けることで、平文でrootユーザのパスワードを指定します。その場合、パスワードが丸見えになるので、KickStartファイルの管理には十分注意してください。

rootpw --plaintext "SyokiPass@9999"
(1)-(b)暗号化したパスワードで記載する場合

"--iscrypted"オプションを付けることで、暗号化された文字列でパスワードを指定します。暗号化されたと言っても時間をかければ解読できるので、KickStartファイルの管理はやはり注意してください。

  • "/etc/shadow"に登録する形式で暗号化した文字列で指定します。
  • 暗号化形式は"auth"で指定され形式になります。例えば、"auth --enableshadow --passalgo=sha512"とある場合は、SHA512形式の暗号化になります。
  • 暗号化されたパスワードの作り方は、次項目(2)を参照して下さい。
# Root password
rootpw --iscrypted $6$WYz7GsXMGCHrJnw.$BoSTW/Ac9vaVvjwB0NVg3.sccEh2g7eZhU7c7BRRx/d8Dxoo7UE70EYyhPEBiemPLxB.Pq0StVaoDIWTWLCFx/

(2)指定する暗号文字列をどうするか?

やり方として2例、(a)pythonで生成する、(b)設定したいパスワードが入った"/etc/shadow"ファイルからコピーする、を説明します。なおネットで見るとopensslコマンドで暗号文字列を生成という記事があるのですが、現在主流のSHA512には対応していないので、この方法は取れません。*3

(3)-(a)pythonで生成する

端的に例を説明すると、"SyokiPass@9999"というパスワードをSHA512形式で暗号化する場合は以下のコマンドになります。

# python -c 'import crypt; print(crypt.crypt("SyokiPass@9999", crypt.METHOD_SHA512))'

sha512は、暗号をより強固なものにするため「暗号したい文字列」と「salt(ソルト)」と呼ばれる文字列を組み合わせ暗号化します。上の例では、"crypt.METHOD_SHA512"の部分がSHA512形式のsalt文字列を生成&入力している部分になります。さらにこの例ではsalt文字列を乱数生成しています。*4

(3)-(b)"/etc/shadow"からコピーする

pythonから生成すればいいので、このやり方は実質不要ですが、一旦インストールした後または、適当なユーザを作成してパスワードを設定しshadowファイルから文字列を抜き出します。":"がフィールドの区切り文字になり、第2フィールドが暗号化された文字列のフィールドになるので、ここをコピーして利用します。

#grep '^root' /etc/shadow
root:$6$WYz7GsXMGCHrJnw.$BoSTW/Ac9vaVvjwB0NVg3.sccEh2g7eZhU7c7BRRx/d8Dxoo7UE70EYyhPEBiemPLxB.Pq0StVaoDIWTWLCFx/::0:99999:7:::

6.その他

(1)GUI/textモードの指定

KickStartファイルの動作確認をする場合はグラフィカルのほうが使いやすいかもしれないですが、最終的に何台ものマシンにセットアップする場合は、textモードが早くて良いと思います。

  • グラフィカル(GUI)モードにする場合
graphical
  • テキストモードにする場合
text

(2)selinux設定

selinuxの設定。無効化(--disabled)、有効化(--enforcing)、警告出力(--permissive)を選択します。

selinux [--disabled|--enforcing|--permissive]

(3)サービス設定

サービスの有効・無効設定を行います。カンマ区切りで複数サービスを指定する場合は、スペースを入れるとそれ以降は認識されません。

  • サービスの有効化
services --enabled=SERVICE1,SERVICE2,SERVICE3
  • サービスの無効化
services --disabled=SERVICE1,SERVICE2,SERVICE3

(4)KickStart完了後の挙動

  • リブートする場合:"reboot --eject" ※"-eject"はdvdを排出するオプション
  • 電源OFFする場合:"poweroff"
  • 一時停止する場合:"halt"

7.設定ファイル例

ks.cfgの設定例です。

#version=DEVEL
# System authorization information
auth --enableshadow --passalgo=sha512
repo --name="Server-HighAvailability" --baseurl=file:///run/install/repo/addons/HighAvailability
repo --name="Server-ResilientStorage" --baseurl=file:///run/install/repo/addons/ResilientStorage

# Use CDROM installation media
cdrom

# Select Install mode. graphical:Use graphical install, text:Use text install.
#graphical
text

# Run the Setup Agent on first boot
firstboot --enable
ignoredisk --only-use=sda
# Keyboard layouts
keyboard --vckeymap=jp --xlayouts='jp'
# System language
lang ja_JP.UTF-8

# Network information
network  --bootproto=dhcp --device=enp0s3 --noipv6 --activate
network  --hostname=testserver

# Root password
rootpw --iscrypted $6$WYz7GsXMGCHrJnw.$BoSTW/Ac9vaVvjwB0NVg3.sccEh2g7eZhU7c7BRRx/d8Dxoo7UE70EYyhPEBiemPLxB.Pq0StVaoDIWTWLCFx/
# System timezone
timezone Asia/Tokyo --isUtc
# System bootloader configuration
bootloader --append=" crashkernel=auto" --location=mbr --boot-drive=sda
# Partition clearing information
clearpart --all --initlabel --drives sda

# Disk partitioning information
part pv.295 --fstype="lvmpv" --ondisk=sda --size=1    --grow
part /boot  --fstype="xfs"   --ondisk=sda --size=500  --label=boot
volgroup rootvg --pesize=4096 pv.295
logvol swap  --fstype="swap" --size=256        --name=swaplv --vgname=rootvg
logvol /home --fstype="xfs"  --size=100        --name=homelv --vgname=rootvg --label="home" 
logvol /     --fstype="xfs"  --size=1   --grow --name=rootlv --vgname=rootvg --label="root" 

%packages
@^infrastructure-server-environment
@base
@compat-libraries
@core
@large-systems
@performance
@security-tools
kexec-tools
telnet
trace-cmd
vim
%end

%addon com_redhat_kdump --enable --reserve-mb='auto'

%end

# Reboot after the installation is complete.(eject DVD media before rebooting)
reboot --eject

*1:このレイアウトはRHELの推奨構成とはことなります。例えばswapが小さかったりするので注意してください。

*2:"--initlabel"は廃止されたようですが、anacondaが自動生成したanaconda-ks.cfgではオプションが付いているので、そのままにしています。参考→32.4. キックスタートのオプション - Red Hat Customer Portal

*3:opensslコマンドがSHA512で使えない件の参考:sha512でハッシュされたsaltつきパスワードを生成するには | Nobwak's Lair

*4:rhelインストールガイドにpythonの例が改定あるのですが、saltの説明が雑なので、しょうがなくKickstartのコードを参考にしています。anaconda/users.py at master · rhinstaller/anaconda · GitHubの"def cryptPassword(password, algo=None):"を参考にしています。

KickStartその1(KickStartによるLinux自動インストール概要)

0.関連記事一覧

1.はじめに

1.1KickStartとは

RHELfedoraなどredhatディストリビューションの、OS自動インストール機能です。*1

1.2ざっくりした使い方

KickStart用のファイルを作成し、インストーラ起動時のオプションで作成ファイルを指定すればOKです。ファイルは、普通にOSインストールするとその時の設定で"/root/anaconda-ks.cfg"ファイルが作成されるので、それを修正して使うのが簡単です。*2

  1. 普通にRHEL/fedoraをインストー
  2. インストール後、"/root/anaconda-ks.cfg"をコピーし編集
  3. 編集したファイルをインストーラから読み込めるよう仕込む。仕込み方法は「3.補足」参照
  4. インストーラでファイルオプション(inst.ks=xxx)を追加して実行
  5. あとは完了するまで待つ。

2.利用手順

2.1ファイル(ks.cfg)の編集

普通にインストールすると、rootのホームディレクトリ直下に"anaconda-ks.cfg"ファイルが作成されているので、このファイルを元に必要な部分を編集します。ファイル名は、特にこだわりがなければKickStartデフォルトの"ks.cfg"にしておくとブート時の設定が少し省けて良いです。*3
■ks.cfgの例(RHELのDVDメディアからインストールする場合の設定例)
設定内容については、こちらの記事を参照して下さい。

#version=DEVEL
# System authorization information
auth --enableshadow --passalgo=sha512
repo --name="Server-HighAvailability" --baseurl=file:///run/install/repo/addons/HighAvailability
repo --name="Server-ResilientStorage" --baseurl=file:///run/install/repo/addons/ResilientStorage

# Use CDROM installation media
cdrom

# Select Install mode. graphical:Use graphical install, text:Use text install.
#graphical
text

# Run the Setup Agent on first boot
firstboot --enable
ignoredisk --only-use=sda
# Keyboard layouts
keyboard --vckeymap=jp --xlayouts='jp'
# System language
lang ja_JP.UTF-8

# Network information
network  --bootproto=dhcp --device=enp0s3 --noipv6 --activate
network  --hostname=testserver

# Root password
rootpw --iscrypted $6$WYz7GsXMGCHrJnw.$BoSTW/Ac9vaVvjwB0NVg3.sccEh2g7eZhU7c7BRRx/d8Dxoo7UE70EYyhPEBiemPLxB.Pq0StVaoDIWTWLCFx/
# System timezone
timezone Asia/Tokyo --isUtc
# System bootloader configuration
bootloader --append=" crashkernel=auto" --location=mbr --boot-drive=sda
# Partition clearing information
clearpart --all --initlabel --drives sda

# Disk partitioning information
part pv.295 --fstype="lvmpv" --ondisk=sda --size=1    --grow
part /boot  --fstype="xfs"   --ondisk=sda --size=500  --label=boot
volgroup rootvg --pesize=4096 pv.295
logvol swap  --fstype="swap" --size=256        --name=swaplv --vgname=rootvg
logvol /home --fstype="xfs"  --size=100        --name=homelv --vgname=rootvg --label="home" 
logvol /     --fstype="xfs"  --size=1   --grow --name=rootlv --vgname=rootvg --label="root" 

%packages
@^infrastructure-server-environment
@base
@compat-libraries
@core
@large-systems
@performance
@security-tools
kexec-tools
telnet
trace-cmd
vim
%end

�don com_redhat_kdump --enable --reserve-mb='auto'

%end

# Reboot after the installation is complete.(eject DVD media before rebooting)
reboot --eject

2.2ファイル検証

作成したファイルは、ksvalidatorコマンドで内容を検証します。
ksvalidatorは通常はインストールされていませんので、yum/dnfコマンドでパッケージを個別にインストールします。

# yum install pykickstart

検証は以下のコマンドで実行します。

$ ksvalidator ks.cfg

KickStartのバージョン毎の構文差異を気にする場合は、インストールするOSバージョンを指定して、検証することもできます。*4

$ ksvalidator -v RHEL7 ks.cfg

2.3インストーラを起動しキックスタートをローディングする

主な方法を以下に列挙します。個人的には、ネットワークが使えるならネット(http/httpsなど)、ネットワークが使えないならフロッピー(判別しやすいから)から設定ファイルを読みこませるのがいいと思っています。

  1. インストーラを起動する。(私はRHELのDVDメディアからブート)
  2. 起動画面で"tabキー"で介入し"ks="、または"inst.ks="オプションでキックスタートファイルの場所を指定する。(下記画面参照)*5
    1. httpの例:"inst.ks=http://192.168.0.1/ks.cfg"
    2. フロッピーの例:"inst.ks=hd:fd0:/ks.cfg"
    3. DVDの例:"inst.ks=cdrom:/ks.cfg"

※ファイルがメディア直下で、ファイル名が"ks.cfg"の場合は、":/ks.cfg"を省略可能です。
f:id:nopipi:20160722080514p:plain

2.4インストール完了

キックスタートファイルが上手く書かれていれば、後は最後まで自動的にインストールされます。

3.補足(kickstartファイルを読み込ませるベストプラクティス)

KickStartファイルをどう読み込ませるか以外に悩みましたので、私なりの考え方を整理しました。

(1)ネットワークが利用可能な環境の場合

ネットワークが利用可能であれば、http/httpsあたりでkickstartファイルを読み込ませるのが最も簡単で確実です。

(2)ネットワークが使えない場合

この場合が悩ましいです。私がおすすめと思った順に記載します。

(2)-1 インストーラをカスタマイズする

インストーラのイメージをカスタマイズして、作成したファイルを組み込み自動的に読み込ませるのが一番確実で、全自動化が可能です。ですが、リビジョンや設定を変更都度に、インストールイメージを作りなおさなければならないのが手間なので、OSインストールの頻度が低い場合は逆に非効率かもしれません。

(2)-2 フロッピーから読み取る

RHELドキュメントには詳細な説明が無いのが気になりますが・・・。ですが個人的には、フロッピーが使える環境であればフロッピーから読み込ませるのが、デバイス名が"fd0"で明確なのもあり、一番無難な気がします。*6

(2)-3 KicStartファイル専用のdvd(isoファイル)を準備して差し替える

kickStartのファイルをisoまたはDVDにし、インストーラで差し替えて利用する方法です。(オプションは、"inst.ks=cdrom/ks.cfg"という感じです。)"Plese Insert CDROM containing"というメッセージが表示されたらDVDを差し替えますが、ロックがかかってejectできなかったりするようです。

(2)-4 USBメモリor外付けHDDを利用する

RHELドキュメントを見ると、USBメモリか外付HDDから読み込むのが無難な方法です。ですが、インストールするディスク構成が異なるとデバイス名が変わるのが難点です。UUIDでデバイスを指定する方法もあるのですが、インストールメディアをカスタマイズせず、毎回"ks="オプションを手打ちする場合は長すぎて面倒です。

4.リファレンス(kickstartドキュメント)

必要な情報は大方、利用するRHEL/fedoraバージョンの「インストールガイド」の終盤にある「キックスタートを使ったインストール」という章に載っています。

*1:RHEL/Fedoraインストーラであるanacondaに含まれる機能です。kickStartを含むanacondaは、redhat社の「Red Hat Installer Engineering Team」が開発しており、ソース&ドキュメントはgithub(Red Hat Installer Engineering Team · GitHub)で公開されています。

*2:以前はファイル作成用のGUIがありましたが、今は開発が放置されているので利用は推奨されないようですインストールガイド 23.2. キックスタートを使ったインストールの実行方法の重要を参照

*3:anacondaの中のdracut用モジュールに"fetch-kickstart-disk"というシェルがあり、そこでファイルのパスのデフォルトが"/ks.cfg"と定義されています。

*4:指定できるバージョン一覧は、"ksvalidator -l dummy"コマンドで確認できます。ファイルパスの文字を何かしら入れないとエラーになるあたりが微妙ですが。

*5:どちらでも利用可能ですが、以前の書き方が"ks="で、最近は"inst.ks="が基本のようです。

*6:以前は、ks=floppyで読み込めましたが、今はks=hd:fd0のように指定します。

Macbook Air(2010/A1370)にUbuntu16.04 LTS(Xenial Xerus)を入れてみた

1.はじめに

この記事は下記記事の焼き直しで、MacbooAir3.1(2010年:A1370)にUbuntu16.04をインストールした記録です。
nopipi.hatenablog.com

前提は以下の通りです。

  • 入れる箱(Mac)
    • Macbook Air A1370(2010年モデル)
      • 機種名/Model: MacBookAir3.1 / A1370
      • 液晶サイズ 11.6
      • CPU/Mem/HDD】Core2Duo 1.4GHz / 2GB / SSD
  • 入れるもの
    • Ubuntu16.04 LTS(Xenial Xerus) ※今回は日本語Remix版を利用
  • インストールメディア(USBブート)作成環境
    • Windows10
    • USBブートメディア作成ツール: "Universal-USB"

2.準備(インストールメディア)

ubuntuのインストール用メディアのisoをUSBメモリに突っ込んで、USBメモリブートでインストールします。

インストールメディアを用意

ubuntuからダウンロード

USBメモリブートメディア作成

今回は、"Universal-USB"というツールを利用しました。
Universal USB Installer - Easy as 1 2 3 | USB Pen Drive Linux
手順は、下記サイトを参考にしています。

3.インストール

  1. 作成したUSBメモリMacbookに差し、「オプションキー」を押しながら起動します。
  2. ブート可能なメディア一覧がでるので、USBメモリを選択(下記画像参照)

f:id:nopipi:20160604001041p:plain

  1. 後は普通にインストール
    1. キーボード設定は、「日本語」->「日本語(Macintosh)」を選択。
    2. それ以外は、Macbook固有で悩むところはないです。

4.MacBook用のubuntu設定

ファンクションキーの反転

初期状態では、ファンクションキーは音声や液晶の明るさ調整がメインで、F1やF2とかファンクションキーとして利用する場合は、fnキーと組み合わせる必要があります。ですが、日本語変換の時面倒なので機能を反転させます。
以下のページを参考にしました。

$ sudo vi /etc/rc.local 
下記の行を追加
echo 2 > /sys/module/hid_apple/parameters/fnmode

マウス変更

2本指で操作の設定。→デフォルトでONのため設定不要。
設定は、左バーの「システム設定」→「マウスとタッチパッド」を選択して設定。
f:id:nopipi:20151122165023p:plain

5.使いやすくするために

ランチャーへの登録

デフォルトではターミナルが、左メニューバー(Launcher)にないので追加します。

  1. ランチャーの一番上のボタンを押し検索画面を出す
  2. 検索ボックスから「Ter・・・」と入力すると、ターミナルが表示されるので実行する。
  3. 実行するとlauncherに実行アプリのボタンが追加されるので、右クリックして「Launcherに登録」を実行

アップデート

立ち上げて暫くするとアップデートを促するメニューが出てそれを実行すればよいですが、手動実行する場合は以下の通り実行します。

GUIから実行
  1. 検索から「update」と入力し、アプリを実行
CLIで実行

ターミナルから以下を実行します。

sudo apt-get upgrade

パッケージの追加インストール

sudo apt-get install vim
sudo apt-get install openssh-server
sudo apt-get install gimp 

ntpサーバ設定

ntpの接続先サーバを国内の"ntp.nict.jp"に変更する。

●/etc/systemd/timesyncd.conf

[Time]
NTP=ntp.nict.jp  <<="ntp.nict.jp"を追加する
#NTP=
#FallbackNTP=ntp.ubuntu.com
サービスの再起動と状態確認
$ sudo systemctl -l restart systemd-timesyncd
$ sudo systemctl -l status systemd-timesyncd
● systemd-timesyncd.service - Network Time Synchronization
   Loaded: loaded (/lib/systemd/system/systemd-timesyncd.service; enabled; vendor preset: enabled)
  Drop-In: /lib/systemd/system/systemd-timesyncd.service.d
           └─disable-with-time-daemon.conf
   Active: active (running) since 月 2016-06-06 17:01:54 JST; 2s ago
     Docs: man:systemd-timesyncd.service(8)
 Main PID: 2948 (systemd-timesyn)
   Status: "Synchronized to time server 133.243.238.164:123 (ntp.nict.jp)."
   CGroup: /system.slice/systemd-timesyncd.service
           └─2948 /lib/systemd/systemd-timesyncd

 6月 06 17:01:54 xxx systemd[1]: Starting Network Time Synchronization...
 6月 06 17:01:54 xxx systemd[1]: Started Network Time Synchronization.
 6月 06 17:01:54 xxx systemd-timesyncd[2948]: Synchronized to time server 133.243.238.164:123 (ntp.nict.jp).

その他Tips

  • 日本語変換の切り替え
    • 「Control+Space」で切り替え。

gccのインラインアセンブラで使えるx86系の汎用レジスタの制御子(Constraints)

一覧

インラインアセンブラ
制御子
レジスタ名称
x86(32bit)x86_64(64bit)
aeaxrax
bebxrbx
cecxrcx
dedxrdx
Sesirsi
Dedirdi
r8-r8
r9-r9
r10-r10
r11-r11
r12-r12
r13-r13
r14-r14
r15-r15

32bitアプリの2038年問題に対してglibc介さずシステムコールを直接呼べば何とかなるかなという浅はかな考えがやっぱり浅はかだった件

はじめに

ラノベのようなタイトルの通り、
ですが。。。。

「そりゃそうだろ、うまく行ってしまったら32bitアプリとの互換性が維持できないだろうさ」という冷やかな視線を感じますが(><)、せっかく試したのでまとめます。

32bitアプリの2038年問題回避方法

2038年問題とは、32bitアプリケーションでは通常"符号ありlong int"で扱うため、2038年でオーバフローする問題です。
その回避策として一般的なのが、独自に"long long int"で64bitの変数を作るか、"符号なしlong int"で処理という方法らしいです。(wikipediaによると)

標準のCライブラリ(glibcとか)は当然"符号ありlong int"なので、この回避策をするためには、時刻処理を何らかの形で独自実装するしかありません。
例えば下記のような方法で、補正をかけるラップ関数を実装する方法などです。(結論から言うと下記リンク先の対応が現実解だったのですが・・・)

今回の実験の安直な発想

ところで、昨今のlinuxサーバ(RHEL)は64bitが普通になっており、その場合カーネル内部では時刻処理も64bitで処理されています。(long変数は、32bit環境の場合は32bit、64bit環境の場合は64bitのため)
そこでカーネルから時刻情報を取得する場合は、32bit環境で、直接カーネル内部の64bit時刻を取得することはできないかなぁ~と思い、安直にCライブラリを使わずアセンブラで直接呼びだしてみたら何かできないかなと思った次第です。

実験のコード

コードの説明

カーネルから時刻取得するためには、clock_gettimeのシステムコールを利用します。比較で普通にglibc関数を利用する方法と、アセンブラで呼びだす両方を実行してみます。
具体的には下記コードでは、32bit/64bit環境それぞれで、下記処理をしています。

  1. glibcのclock_gettime()関数を利用して時刻取得する(普通の方法)
  2. (実験メイン)アセンブラで直接clock_gettimeシステムコールを呼びだし時刻取得する
    1. 32bitの場合、(a)32bitのtimespec構造体、(b)64bitのtimespec構造体(long long int)それぞれで取得する
    2. 64bitの場合、(a)64bitのtimespec構造体で取得する。
    3. なおアセンブラで呼びだす場合のtimespec構造体は、32/64bit環境のbit長差異をないことを明確にするため、32bit長ではint型、64bitでは"long long int"で独自定義している

なお、いろいろぐちゃぐちゃやっていたので、余計なコードが入っていますが、ご容赦ください。

コード(time.c)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#define _GNU_SOURCE
#include <unistd.h>
#include <sys/syscall.h>
#include <sys/types.h>

#define SYS_clock_gettime32 20
#define SYS_clock_gettime64 228


struct timespec32_test {
	int tv_sec;
	int tv_nsec;
};

struct timespec64_test {
	long long int tv_sec;
	long long int tv_nsec;
};


void printf_timespec(struct timespec *tp, int ret, char *mes)
{

	printf("%-40s " ,mes);
	printf("tv_sec=%-12ld ",tp->tv_sec);
	printf("tv_nsec=%-12ld ",tp->tv_nsec);
	printf("ret=%d\n",ret);

}

void printf_timespec32_test(struct timespec32_test *tp, int ret, char *mes)
{

	printf("%-40s ",mes);
	printf("tv_sec=%-12d ",tp->tv_sec);
	printf("tv_nsec=%-12d ",tp->tv_nsec);
	printf("ret=%d\n",ret);

}

void printf_timespec64_test(struct timespec64_test *tp, int ret, char *mes)
{
	printf("%-40s ",mes);
	printf("tv_sec=%-12lld ",tp->tv_sec);
	printf("tv_nsec=%-12lld ",tp->tv_nsec);
	printf("ret=%d\n",ret);
}

int main()
{
	struct timespec tp;
	struct timespec64_test tp64;
#if defined(__i386__) || defined(__ILP32__)
	struct timespec32_test tp32;
#endif
	pid_t  pid;
	int ret;
	char *mes;

	/* info */
	pid=getpid();
	printf("PID=%d\n",pid);

	mes = "glibc clock_gettime-long int";	
	tp.tv_sec=tp.tv_nsec=0;
	ret = clock_gettime(CLOCK_REALTIME,&tp);
	printf_timespec(&tp, ret, mes);

#if defined(__i386__) || defined(__ILP32__)
	/* 32bit application */
	mes = "Assemble=>i386 int 0x80-timespec-32bit";
	tp32.tv_sec=tp32.tv_nsec=0;
	__asm__ volatile(
	        "int $0x80;"
	        :"=a"(ret)
	        :"0"(SYS_clock_gettime),
	         "b"(CLOCK_REALTIME),
	         "c"(&tp32)
	);
	printf_timespec32_test(&tp32, ret, mes);

	mes = "Assemble=>i386 int 0x80-timespec-64bit";
	tp64.tv_sec=tp64.tv_nsec=0;
	__asm__ volatile(
	        "int $0x80;"
	        :"=a"(ret)
	        :"0"(SYS_clock_gettime),
	         "b"(CLOCK_REALTIME),
	         "c"(&tp64)
	);
	printf_timespec64_test(&tp64, ret, mes);

#else
	/* 64bit application */
	mes = "Assemble=>x86_64 syscall-timespec-64bit";
	tp64.tv_sec=tp64.tv_nsec=0;
	__asm__ volatile(
	        "syscall;"
	        :"=a"(ret)
	        :"0"(SYS_clock_gettime),
	         "D"(CLOCK_REALTIME),
	         "S"(&tp64)
	        :"memory"
	);
	printf_timespec64_test(&tp64, ret, mes);
#endif

	return(EXIT_SUCCESS);
}

実行結果

64bit環境

何も細工していないので、アセンブラで呼びだしても普通に応答が帰ってきます。

$ gcc -m64 -o time64 -g3 -Wall -O0  time.c
$ ./time64 
PID=5434
glibc clock_gettime-long int             tv_sec=1452509660   tv_nsec=790867319    ret=0
Assemble=>x86_64 syscall-timespec-64bit  tv_sec=1452509660   tv_nsec=790892879    ret=0

32bit環境

32bitの時刻構造体のポインタを渡したときは普通ですが、64bitの時刻構造体のポインタを無理やり渡しても、当然おかしな結果になっているのがよく分かります(^^;

$ gcc -m32 -o time32 -g3 -Wall -O0  time.c
$ ./time32
PID=5426
glibc clock_gettime-long int             tv_sec=1452509515   tv_nsec=540033119    ret=0
Assemble=>i386 int 0x80-timespec-32bit   tv_sec=1452509515   tv_nsec=540054759    ret=0
Assemble=>i386 int 0x80-timespec-64bit   tv_sec=2319584530896488779 tv_nsec=0            ret=0

カーネル挙動を確認する

当然といえば、当然の結果ですが。。。
念のための裏付けで、カーネル内部で32bitのシステムコールが呼ばれた場合どのような挙動をするのかを、ftraceでカーネル内部でどの様な関数が呼びだされているか確認してみました。

ftrace(trace-cmd)での確認方法

以下のコマンドでカーネルトレースを取得します。最後の実行コマンドをそれぞれ"./time64"、"./time32"とすることで32/64bit両環境のトレースを取得します。

$ sudo trace-cmd record -p function_graph -g SyS_clock_gettime -g compat_SyS_clock_gettime ./time64 
$ trace-cmd report

trace-cmdコマンドの詳細は(ftrace)trace-cmdでfunction_graphを使ってみる - のぴぴのメモを参照。

トレース結果

64bitと32bitを比較すると、32bitアプリから呼びだした場合は、cpmpat_sys_clock_gettime()なる関数でラップされているのが分かります。(blogの横幅の関係で、関数部分のみ記載しています)。なおカーネルは、ubuntu 14.04の"Linux version 3.19.0-43-generic (buildd@lgw01-16)"になります。

64bitアプリからのカーネルトレース(抜粋)
 |  sys_clock_gettime() {
 |    posix_clock_realtime_get() {
 |      getnstimeofday64() {
 |        __getnstimeofday64() {
 |          read_hpet();
 |        }
 |      }
 |    }
 |  }
32bitアプリからのカーネルトレース(抜粋)
 |  compat_sys_clock_gettime() {
 |    sys_clock_gettime() {
 |      posix_clock_realtime_get() {
 |        getnstimeofday64() {
 |          __getnstimeofday64() {
 |            read_hpet();
 |          }
 |        }
 |      }
 |    }
 |    compat_put_timespec() {
 |      __compat_put_timespec();
 |    }
 |  }

では、compat_sys_clock_gettime()ではどんな事をしているのでしょうか。

  • compat_sys_clock_gettime()は、/kernel/compat.cに実装
  • まず、sys_clock_gettime()を呼び出し(この時はtimespecは64bit。下記コードでts)
  • その後、copmpat_put_timespec()で、システムコールの引数に渡すデータを、カーネル空間からユーザ空間の所定位置にコピーする。(下記コードでtp)
  • で、そのcopmpat_put_timespec()内部で、64bitから32bitにデータを落としているらしい。
 740 long compat_sys_clock_gettime(clockid_t which_clock,
 741                 struct compat_timespec __user *tp)
 742 {
 743         long err;
 744         mm_segment_t oldfs;
 745         struct timespec ts;
 746 
 747         oldfs = get_fs();
 748         set_fs(KERNEL_DS);
 749         err = sys_clock_gettime(which_clock,
 750                                 (struct timespec __user *) &ts);
 751         set_fs(oldfs);
 752         if (!err && put_compat_timespec(&ts, tp))
 753                 return -EFAULT;
 754         return err;
 755 }

実際にデータ変換(64bit->32bit)をしているのはinlineアセンブラっぽい

  • arch/x86/include/asm/uaccess.h
 411 #define __put_user_asm(x, addr, err, itype, rtype, ltype, errret)       \
 412         asm volatile(ASM_STAC "\n"                                      \
 413                      "1:        mov"itype" %"rtype"1,%2\n"              \
 414                      "2: " ASM_CLAC "\n"                                \
 415                      ".section .fixup,\"ax\"\n"                         \
 416                      "3:        mov %3,%0\n"                            \
 417                      "  jmp 2b\n"                                       \
 418                      ".previous\n"                                      \
 419                      _ASM_EXTABLE(1b, 3b)                               \
 420                      : "=r"(err)                                        \
 421                      : ltype(x), "m" (__m(addr)), "i" (errret), "0" (err))

ということで、カーネル内部のcpmpat_XXXXXXX関数で、32bitアプリ向けに64bit→32bitのデータ変換が行われているため、どうやっても32bitアプリでカーネルから64bitの時刻データを取得するのは難しそうです。