- 投稿日:2019-06-22T19:07:26+09:00
権限設定の777とか755って何?って話。
- 投稿日:2019-06-22T19:06:30+09:00
権限設定
permission defined
初学者のうちとか特によくこれを見ません?
鬱陶しいですよね。
まあ英語そのまま権限が無いという意味なんですけど。ターミナルsudo 実行したいコマンド
みたいにしてrootユーザーからとりあえず操作するってこともあると思います。
だけど権限が無いなら付与したく無い?という話です。権限の見方
問題のファイルがあるディレクトリまで移動して以下のコマンドを実行します。
ターミナルls -l
すると
drwxr-xr-x
こういうのが出てきます。
とりあえず一番左を飛ばすと9文字ありますよね。
3つずつでr(read),w(write),x(実行、英語忘れた)という風に別れています。当然3つあるということはそれぞれが別のものにたいしてなのですが、、
左からowner(所有者),group(グループ),other(他)という風に別れています。続きの話も書こうと思っていましたが
めんどくさくなってきたので長いとわかりにくいのでこんなもんで切ってまた次回続きを書きます。
- 投稿日:2019-06-22T11:59:37+09:00
OCI Compute/DatabaseでVNCを構成する Part 1
下書中なのに間違ってアップしてしまいました。あとで修正します。
1. はじめに
過去4回にわたってWindowsクライアントからLinux上のGUIアプリを実行する方法を説明した。これまではVcXsrvやXmingなどのXサーバに焦点を当てたが、今回はVNCを取り上げる。
- Windowsクライアントを使って…(1)→全体像を説明
- Windowsクライアントを使って…(2)→設定&踏み台なし接続
- Windowsクライアントを使って…(3)→踏み台あり接続(連続ログイン)
- Windowsクライアントを使って…(4)→踏み台あり接続(多段ssh)
1-2. TL;DR
- VNCは、リモートコンピュータのデスクトップを操作するツールとして昔から使われている
- オンプレミスでも有用だが、ローカルアクセスができないクラウドでは重要度が増している
- いろいろなところで取り上げられているネタだが、微妙に正しくないというか、最適ではない記述が多い
1-3. 利用環境
今回はOCI Computeを使用しているが、OCI Databaseにも対応している。また他のクラウドサービスでも、VNCの設定はほとんど同じはずだ。
- Oracle Linux 7 / CentOS 7などのRHEL7互換ディストリビューション
- Oracle Linux 6 / CentOS 6などのRHEL6互換ディストリビューション
- Oracle Cloud Infrastructure Compute / Database
- sshクライアント: PuTTY 0.71
1-4. 前提条件
前提条件は以下のとおり。
- インターネット経由でアクセスするときはVNCサーバにグローバルIPが割り当てられていること。多段sshを利用すればプライベートサブネットでもよいが、話が複雑になるので説明しない
- 専用線(FastConnect)やインターネットVPN(IPSev VPN)でアクセスするときはグローバルIPは不要
- Yumリポジトリにアクセスできること
1-5. 参考資料
VNCサーバについては、Linuxディストリビューションベンダのマニュアルが充実している。
7系マニュアル:
- Oracle Linux 管理者ガイド, リリース7「VNCサービス構成」
- Oracle Linux Administrator's Guide for Release 7 "Configuring a VNC Server"
- Red Hat Enterprise Linux 7 システム管理者ガイド「TigerVNC」
6系マニュアル:
15.3.2. CONNECTING TO A VNC SERVER
https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/6/html/deployment_guide/s1-connecting-to-vnc-server#sec-Configuring_the_Firewall_for_VNCその他資料:
2. VNCとは
VNCの詳細はどこかで調べてもらうとして、昔から使われていることや、さまざまな使用方法があるのが特徴だろう。
とくに起動/設定方法の多様さは、利用者を惑わすのに十分。サービスで起動することもできるし、一般ユーザーが起動することもできる。さらにはXDMCPやxrdpと組み合わせることもできる。うーん。
前回説明したXcXsrv/XmingなどのXサーバと比べたときの特徴は次のとおり。
- 単一のウインドウだけでなく、フルデスクトップ環境を利用できる
- インストールしないで、ファイルを配置するだけで使えるWindowsクライアントがある
- 通信が暗号化されないので、インターネットなどで利用するときはSSHトンネリングで暗号化する必要がある
VNCの典型的なユースケース
しかし弱点もある。次のような条件がある場合だ。
外部ネットワークに接続するには、オンプレミスの外部アクセス用踏み台サーバを経由する必要がある
外部アクセス用の踏み台サーバにXcXsrv/Xmingがインストールされていない
外部アクセス用の踏み台サーバには管理者権限がなく、追加のプログラムをインストールできない
XcXsrv/Xmingは事前にインストールが必要なソフトウェアなので、上記の環境では利用できない。そのときでも使えるのがVNCだ。VNCクライアントには、ファイルを置くだけで使えるものがあるからだ。
3. 設定の流れ
設定手順は以下のとおり。はじめにLinuxサーバにVNCサーバを設定し、次にWindowsクライアントで設定する。
4. Linuxサーバを設定する
Linuxサーバでは、VNCサーバのインストールと設定を行う。
4-1. Yumリポジトリにアクセスできるか確認する
Yumリポジトリにアクセスできるか確認する。以下のように表示されればアクセスできている。
# yum repolist enabled Loaded plugins: langpacks, ulninfo repo id repo name status ol7_UEKR5/x86_64 Latest Unbreakable Enterprise Kernel Rele 163 ol7_addons/x86_64 Oracle Linux 7Server Add ons (x86_64) 336 ol7_developer/x86_64 Oracle Linux 7Server Development Packages 831 ol7_developer_EPEL/x86_64 Oracle Linux 7Server Development Packages 26,805 ol7_ksplice Ksplice for Oracle Linux 7Server (x86_64) 2,378 ol7_latest/x86_64 Oracle Linux 7Server Latest (x86_64) 13,107 ol7_optional_latest/x86_64 Oracle Linux 7Server Optional Latest (x86 9,958 ol7_software_collections/x86_64 Software Collection Library release 3.0 p 13,856 repolist: 67,434アクセスできないときは以下の設定を確認する。
- Internet GatewayやNAT Gateway、Service Gatewayなどの配置
- ルートテーブルの設定
またOCI Databaseは、デフォルトではYumリポジトリにアクセスできない。以下のエントリを参考に設定すること。
4-2. デスクトップ環境をインストールする
デスクトップ環境をインストールする。6系と7系では選択するパッケージグループが違うので、利用環境に応じて実行する。
7系Linux OS
yum groupinstall graphical-server-environment -y
ヒント:グループインストールのテクニック
以下のような表記をよく見かけるが、あまりかっこよくない(超個人的見解)。
yum groupinstall "Server with GUI"
インストールグループにはIDがつけられているので、それを使ったほうがオススメ。
yum groupinstall graphical-server-environment
インストールグループのIDは以下のコマンドで表示できる。
--disablerepo
や--enablerepo
は省略可能だが、有効なYumリポジトリがたくさんあってわかりづらいので指定している。Oracle Linux 6のときはol7_latest
ではなくol6_latest
。またCentOSはバージョン共通でbase
。7系の出力結果
yum --disablerepo=* --enablerepo=ol7_latest -v grouplist ---以下画面表示--- Available Environment Groups: Minimal Install (minimal) Infrastructure Server (infrastructure-server-environment) File and Print Server (file-print-server-environment) Basic Web Server (web-server-environment) Virtualization Host (virtualization-host-environment) Server with GUI (graphical-server-environment) Available Groups: Compatibility Libraries (compat-libraries) Console Internet Tools (console-internet) Development Tools (development) Graphical Administration Tools (graphical-admin-tools) Legacy UNIX Compatibility (legacy-unix) Scientific Support (scientific) Security Tools (security-tools) Smart Card Support (smart-card) System Administration Tools (system-admin-tools) System Management (system-management) Done
6系の出力結果
yum --disablerepo=* --enablerepo=ol6_latest -v grouplist ---以下画面表示--- Installed Groups: Base (base) E-mail server (mail-server) Fonts (fonts) Graphical Administration Tools (graphical-admin-tools) Hardware monitoring utilities (hardware-monitoring) Legacy UNIX compatibility (legacy-unix) Legacy X Window System compatibility (legacy-x) Network file system client (network-file-system-client) Networking Tools (network-tools) Performance Tools (performance) Perl Support (perl-runtime) System administration tools (system-admin-tools) iSCSI Storage Client (storage-client-iscsi) Installed Language Groups: Japanese Support (japanese-support) [ja] Available Groups: Additional Development (additional-devel) Backup Client (backup-client) Backup Server (backup-server) CIFS file server (cifs-file-server) Client management tools (client-mgmt-tools) Compatibility libraries (compat-libraries) Console internet tools (console-internet) Debugging Tools (debugging) Desktop (basic-desktop) Desktop Debugging and Performance Tools (desktop-debugging) Desktop Platform (desktop-platform) Desktop Platform Development (desktop-platform-devel) Development tools (development) Dial-up Networking Support (dial-up) Directory Client (directory-client) Directory Server (directory-server) Eclipse (eclipse) Emacs (emacs) FCoE Storage Client (storage-client-fcoe) FTP server (ftp-server) General Purpose Desktop (general-desktop) Graphics Creation Tools (graphics) High Availability (ha) High Availability Management (ha-management) Identity Management Server (identity-management-server) Infiniband Support (infiniband) Input Methods (input-methods) Internet Browser (internet-browser) Java Platform (java-platform) KDE Desktop (kde-desktop) Large Systems Performance (large-systems) Load Balancer (load-balancer) Mainframe Access (mainframe-access) Messaging Client Support (system-management-messaging-client) MySQL Database client (mysql-client) MySQL Database server (mysql) NFS file server (nfs-file-server) Network Infrastructure Server (network-server) Network Storage Server (storage-server) PHP Support (php) PostgreSQL Database client (postgresql-client) PostgreSQL Database server (postgresql) Print Server (print-server) Printing client (print-client) Remote Desktop Clients (remote-desktop-clients) Resilient Storage (resilient-storage) Ruby Support (ruby-runtime) SNMP Support (system-management-snmp) Scalable Filesystems (scalable-file-systems) Scientific support (scientific) Security Tools (security-tools) Server Platform (server-platform) Server Platform Development (server-platform-devel) Smart card support (smart-card) Somali Support (somali-support) Storage Availability Tools (storage-client-multipath) System Management (system-management) Systems Management Messaging Server support (system-management-messaging-server) TeX support (tex) Technical Writing (technical-writing) TurboGears application framework (turbogears) Virtualization (virtualization) Virtualization Client (virtualization-client) Virtualization Platform (virtualization-platform) Virtualization Tools (virtualization-tools) Web Server (web-server) Web Servlet Engine (web-servlet) Web-Based Enterprise Management (system-management-wbem) X Window System (x11) Available Language Groups: Afrikaans Support (afrikaans-support) [af] Albanian Support (albanian-support) [sq] Amazigh Support (amazigh-support) [ber] Arabic Support (arabic-support) [ar] Armenian Support (armenian-support) [hy] Assamese Support (assamese-support) [as] Azerbaijani Support (azerbaijani-support) [az] Basque Support (basque-support) [eu] Belarusian Support (belarusian-support) [be] Bengali Support (bengali-support) [bn] Bhutanese Support (bhutanese-support) [dz] Brazilian Portuguese Support (brazilian-support) [pt_BR] Breton Support (breton-support) [br] Bulgarian Support (bulgarian-support) [bg] Catalan Support (catalan-support) [ca] Chhattisgarhi Support (chhattisgarhi-support) [hne] Chichewa Support (chichewa-support) [ny] Chinese Support (chinese-support) [zh] Coptic Support (coptic-support) [cop] Croatian Support (croatian-support) [hr] Czech Support (czech-support) [cs] Danish Support (danish-support) [da] Dutch Support (dutch-support) [nl] English (UK) Support (british-support) [en_GB] Esperanto Support (esperanto-support) [eo] Estonian Support (estonian-support) [et] Ethiopic Support (ethiopic-support) [am] Faroese Support (faroese-support) [fo] Fijian Support (fijian-support) [fj] Filipino Support (filipino-support) [fil] Finnish Support (finnish-support) [fi] French Support (french-support) [fr] Frisian Support (frisian-support) [fy] Friulian Support (friulian-support) [fur] Gaelic Support (gaelic-support) [gd] Galician Support (galician-support) [gl] Georgian Support (georgian-support) [ka] German Support (german-support) [de] Greek Support (greek-support) [el] Gujarati Support (gujarati-support) [gu] Hebrew Support (hebrew-support) [he] Hiligaynon Support (hiligaynon-support) [hil] Hindi Support (hindi-support) [hi] Hungarian Support (hungarian-support) [hu] Icelandic Support (icelandic-support) [is] Indonesian Support (indonesian-support) [id] Interlingua Support (interlingua-support) [ia] Inuktitut Support (inuktitut-support) [iu] Irish Support (irish-support) [ga] Italian Support (italian-support) [it] Kannada Support (kannada-support) [kn] Kashmiri Support (kashmiri-support) [ks] Kashubian Support (kashubian-support) [csb] Kazakh Support (kazakh-support) [kk] Khmer Support (khmer-support) [km] Kinyarwanda Support (kinyarwanda-support) [rw] Konkani Support (konkani-support) [kok] Korean Support (korean-support) [ko] Kurdish Support (kurdish-support) [ku] Lao Support (lao-support) [lo] Latin Support (latin-support) [la] Latvian Support (latvian-support) [lv] Lithuanian Support (lithuanian-support) [lt] Low Saxon Support (low-saxon-support) [nds] Luxembourgish Support (luxembourgish-support) [lb] Macedonian Support (macedonian-support) [mk] Maithili Support (maithili-support) [mai] Malagasy Support (malagasy-support) [mg] Malay Support (malay-support) [ms] Malayalam Support (malayalam-support) [ml] Maltese Support (maltese-support) [mt] Manx Support (manx-support) [gv] Maori Support (maori-support) [mi] Marathi Support (marathi-support) [mr] Mongolian Support (mongolian-support) [mn] Myanmar (Burmese) Support (burmese-support) [my] Nepali Support (nepali-support) [ne] Northern Sotho Support (northern-sotho-support) [nso] Norwegian Support (norwegian-support) [nb] Occitan Support (occitan-support) [oc] Oriya Support (oriya-support) [or] Persian Support (persian-support) [fa] Polish Support (polish-support) [pl] Portuguese Support (portuguese-support) [pt] Punjabi Support (punjabi-support) [pa] Romanian Support (romanian-support) [ro] Russian Support (russian-support) [ru] Sanskrit Support (sanskrit-support) [sa] Sardinian Support (sardinian-support) [sc] Serbian Support (serbian-support) [sr] Sindhi Support (sindhi-support) [sd] Sinhala Support (sinhala-support) [si] Slovak Support (slovak-support) [sk] Slovenian Support (slovenian-support) [sl] Southern Ndebele Support (southern-ndebele-support) [nr] Southern Sotho Support (southern-sotho-support) [st] Spanish Support (spanish-support) [es] Swahili Support (swahili-support) [sw] Swati Support (swati-support) [ss] Swedish Support (swedish-support) [sv] Tagalog Support (tagalog-support) [tl] Tajik Support (tajik-support) [tg] Tamil Support (tamil-support) [ta] Telugu Support (telugu-support) [te] Tetum Support (tetum-support) [tet] Thai Support (thai-support) [th] Tibetan Support (tibetan-support) [bo] Tsonga Support (tsonga-support) [ts] Tswana Support (tswana-support) [tn] Turkish Support (turkish-support) [tr] Turkmen Support (turkmen-support) [tk] Ukrainian Support (ukrainian-support) [uk] Upper Sorbian Support (upper-sorbian-support) [hsb] Urdu Support (urdu-support) [ur] Uzbek Support (uzbek-support) [uz] Venda Support (venda-support) [ve] Vietnamese Support (vietnamese-support) [vi] Walloon Support (walloon-support) [wa] Welsh Support (welsh-support) [cy] Xhosa Support (xhosa-support) [xh] Zulu Support (zulu-support) [zu] Done
6系Linux OS
yum groupinstall basic-desktop general-desktop japanese-support -y
4-3. VNCサーバをインストールする
次にVNCサーバをインストールする。3D CGライブラリの
mesa-libEGL
は必須ではないが、firefoxが起動できないという報告があるのでインストールする。yum install tigervnc-server mesa-libEGL -y
使用環境によってインストールされるパッケージに違いはある。
インストールされるパッケージ一覧
=================================================================================================== Package Arch Version Repository Size =================================================================================================== Installing: mesa-libEGL x86_64 18.0.5-4.el7_6 ol7_latest 101 k tigervnc-server x86_64 1.8.0-13.el7 ol7_latest 214 k Installing for dependencies: gnutls x86_64 3.3.29-9.el7_6 ol7_latest 680 k libXdamage x86_64 1.1.4-4.1.el7 ol7_latest 20 k libXdmcp x86_64 1.1.2-6.el7 ol7_latest 34 k libXfont2 x86_64 2.0.3-1.el7 ol7_latest 143 k libXinerama x86_64 1.1.3-2.1.el7 ol7_latest 13 k libXrandr x86_64 1.5.1-2.el7 ol7_latest 27 k libXxf86misc x86_64 1.0.3-7.1.el7 ol7_latest 19 k libdrm x86_64 2.4.91-3.el7 ol7_latest 153 k libglvnd x86_64 1:1.0.1-0.8.git5baa1e5.el7 ol7_latest 89 k libglvnd-egl x86_64 1:1.0.1-0.8.git5baa1e5.el7 ol7_latest 43 k libglvnd-glx x86_64 1:1.0.1-0.8.git5baa1e5.el7 ol7_latest 124 k libjpeg-turbo x86_64 1.2.90-6.el7 ol7_latest 134 k libpciaccess x86_64 0.14-1.el7 ol7_latest 26 k libwayland-client x86_64 1.15.0-1.el7 ol7_latest 32 k libwayland-server x86_64 1.15.0-1.el7 ol7_latest 38 k libxshmfence x86_64 1.2-1.el7 ol7_latest 6.5 k llvm-private x86_64 6.0.1-2.el7 ol7_latest 21 M mesa-dri-drivers x86_64 18.0.5-4.el7_6 ol7_latest 6.6 M mesa-filesystem x86_64 18.0.5-4.el7_6 ol7_latest 17 k mesa-libGL x86_64 18.0.5-4.el7_6 ol7_latest 161 k mesa-libgbm x86_64 18.0.5-4.el7_6 ol7_latest 37 k mesa-libglapi x86_64 18.0.5-4.el7_6 ol7_latest 44 k nettle x86_64 2.7.1-8.el7 ol7_latest 327 k tigervnc-license noarch 1.8.0-13.el7 ol7_latest 28 k tigervnc-server-minimal x86_64 1.8.0-13.el7 ol7_latest 1.0 M trousers x86_64 0.3.14-2.el7 ol7_latest 289 k xkeyboard-config noarch 2.24-1.el7 ol7_latest 833 k xorg-x11-server-utils x86_64 7.7-20.el7 ol7_latest 178 k xorg-x11-xinit x86_64 1.3.4-2.el7 ol7_latest 58 k xorg-x11-xkb-utils x86_64 7.7-14.el7 ol7_latest 102 k Transaction Summary =================================================================================================== Install 2 Packages (+30 Dependent packages) Total download size: 33 M Installed size: 112 M
4-4. VNCサーバを設定する
VNCサーバを複数のユーザーで利用する場合、それぞれ別のポートを割り当てる必要がある。またサービスを利用して起動するときは、OSユーザーを意識して設定ファイルを構成する必要がある。
次の例はシングルユーザーの場合と複数ユーザーの場合の例だ。この仕組みを頭に入れておく必要がある。
1つのOSユーザを同時に1人だけで利用
ポート番号 ディスプレイ番号 OSユーザ名 利用者 5901 :1 opc 不特定多数。ただし同時には使用しない 複数のOSユーザを同時に複数利用者で利用
ポート番号 ディスプレイ番号 OSユーザ名 利用者 5901 :1 opc Aさん 5902 :2 oracle Bさん 5903 :3 opc Cさん 4-3-1. VNCサーバを設定する(7系Linux OS)
- VNCサーバ用ユニット・ファイルのテンプレート
/usr/lib/systemd/system/vncserver@.service
を/etc/systemd/system/
にコピーする。VNCサーバを利用するOSユーザーが1つだけのときはファイル名を変えなくてよいが、複数のOSユーザーで使用するときは
vncserver-<OSユーザー名>@.service
のように変更する。シングルユーザー用
cp /usr/lib/systemd/system/vncserver@.service /etc/systemd/system/vncserver@.service
複数ユーザー用
cp /usr/lib/systemd/system/vncserver@.service /etc/systemd/system/vncserver-opc@.service
注意
Oracleのマニュアルを含め、世間の情報の中には
vncserver-<OSユーザ名>@:1.service
のように、ファイル名の@の次にディスプレイ番号を入れているものがある。しかしファイル名にディスプレイ番号は不要だ。systemdで起動するときにディスプレイ番号を指定すればよい。
2.コピーしたユニットファイルの
<USER>
をOSユーザ名
に変更する。今回は以下のようにopc
に変更する(2箇所)。変更前
ExecStartPre=/bin/sh -c '/usr/bin/vncserver -kill %i > /dev/null 2>&1 || :' ExecStart=/usr/sbin/runuser -l <USER> -c "/usr/bin/vncserver %i" PIDFile=/home/<USER>/.vnc/%H%i.pid ExecStop=/bin/sh -c '/usr/bin/vncserver -kill %i > /dev/null 2>&1 || :'変更後
ExecStartPre=/bin/sh -c '/usr/bin/vncserver -kill %i > /dev/null 2>&1 || :' ExecStart=/usr/sbin/runuser -l opc -c "/usr/bin/vncserver %i" PIDFile=/home/opc/.vnc/%H%i.pid ExecStop=/bin/sh -c '/usr/bin/vncserver -kill %i > /dev/null 2>&1 || :'3.VNCパスワードを設定する。このときは必ず指定のOSユーザに
su
してから実行する。なおパスワードは最低6文字以上。# su - opc $ vncpasswd Password: ★パスワード入力 Verify: ★同じパスワード入力 Would you like to enter a view-only password (y/n)? n A view-only password is not used4.VNCサーバの起動方法は以下の通り。ここでディスプレイ番号を指定する。
systemctl start vncserver@:<display-number>.service
ディスプレイ番号が1のときは次のように指定する。コロンを忘れないように。
sudo systemctl start vncserver-opc@:1.service
5.起動していることを確認する。確認方法はいろいろある。うまくいかないときは
$HOME/.vnc/
配下にログファイルも確認すること。$ sudo systemctl status vncserver-opc@:1.service ---以下画面表示--- ● vncserver-opc@:1.service - Remote desktop service (VNC) Loaded: loaded (/etc/systemd/system/vncserver-opc@.service; disabled; vendor preset: disabled) Active: active (running) since Tue 2019-06-18 22:03:27 JST; 1h 17min ago Process: 9264 ExecStart=/usr/sbin/runuser -l opc -c /usr/bin/vncserver %i (code=exited, status=0/SUCCESS) Process: 9261 ExecStartPre=/bin/sh -c /usr/bin/vncserver -kill %i > /dev/null 2>&1 || : (code=exited, status=0/SUCCESS) Main PID: 9289 (Xvnc) CGroup: /system.slice/system-vncserver\x2dopc.slice/vncserver-opc@:1.service ‣ 9289 /usr/bin/Xvnc :1 -auth /home/opc/.Xauthority -desktop vncsrv:1 (opc) -fp c... Jun 18 22:03:24 vncsrv systemd[1]: Starting Remote desktop service (VNC)... Jun 18 22:03:27 vncsrv systemd[1]: Started Remote desktop service (VNC).netstatもnmapでも5901ポートが使われていることがわかる。
$ netstat -ltp4 Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 0.0.0.0:https 0.0.0.0:* LISTEN - tcp 0 0 0.0.0.0:5901 0.0.0.0:* LISTEN 7425/Xvnc tcp 0 0 0.0.0.0:sunrpc 0.0.0.0:* LISTEN - tcp 0 0 0.0.0.0:6001 0.0.0.0:* LISTEN 7425/Xvnc tcp 0 0 0.0.0.0:ssh 0.0.0.0:* LISTEN$ nmap -Pn ホストのIPアドレス PORT STATE SERVICE 22/tcp open ssh 111/tcp open rpcbind 443/tcp open https 5901/tcp open vnc-1 6001/tcp open X11:1/home/<ユーザー名>/.vnc/vncsrv:1.log
4-3-2. VNCサーバを設定する(6系Linux OS)
VNCSERVERS="display_number:user"
VNCSERVERS="display_number:user display_number:user"
vi /etc/sysconfig/vncservers
/etc/sysconfig/vncserversVNCSERVERS="1:opc"
# service vncserver start Starting VNC server: 1:opc New 'vncsrv6:1 (opc)' desktop is vncsrv6:1 Starting applications specified in /home/opc/.vnc/xstartup Log file is /home/opc/.vnc/vncsrv6:1.log [ OK ]# service vncserver status Xvnc (pid 24161) is running...# netstat -ltp Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 *:sunrpc *:* LISTEN 2323/rpcbind tcp 0 0 *:6001 *:* LISTEN 24161/Xvnc tcp 0 0 *:ssh *:* LISTEN 2742/sshd tcp 0 0 localhost:smtp *:* LISTEN 2865/master tcp 0 0 *:5901 *:* LISTEN 24161/Xvnc tcp 0 0 *:60942 *:* LISTEN 2422/rpc.statd tcp 0 0 *:sunrpc *:* LISTEN 2323/rpcbind tcp 0 0 *:6001 *:* LISTEN 24161/Xvnc tcp 0 0 *:50770 *:* LISTEN 2422/rpc.statd tcp 0 0 *:ssh *:* LISTEN 2742/sshd5. ファイアウォールを設定する(オプション)
5-1. あああああ
5-2. 7系OS
/usr/lib/firewalld/services/vnc-server.xml<?xml version="1.0" encoding="utf-8"?> <service> <short>Virtual Network Computing Server (VNC)</short> <description>A VNC server provides an external accessible X session. Enable this option if you plan to provide a VNC server with direct access. The access will be possible for displays :0 to :3. If you plan to provide access with SSH, do not open this option and use the via option of the VNC viewer.</description> <port protocol="tcp" port="5900-5903"/> </service>firewall-cmd --permanent --add-service=vnc-server --zone=public firewall-cmd --reload
# firewall-cmd --list-all public (active) target: default icmp-block-inversion: no interfaces: ens3 sources: services: ssh dhcpv6-client vnc-server ports: 443/tcp protocols: masquerade: no forward-ports: source-ports: icmp-blocks: rich rules:$ nmap -Pn localhost PORT STATE SERVICE 22/tcp open ssh 25/tcp open smtp 111/tcp open rpcbind 5901/tcp open vnc-1 6001/tcp open X11:1 Nmap done: 1 IP address (1 host up) scanned in 0.10 secondsiptables -A INPUT -p tcp -m tcp --dport 5901 -j ACCEPT
$ sudo iptables -A INPUT -p tcp -m tcp --dport 5901 -j ACCEPT [opc@vncsrv6 ~]$ service iptables save iptables: Only usable by root. [WARNING] [opc@vncsrv6 ~]$ sudo service iptables save iptables: Saving firewall rules to /etc/sysconfig/iptables:[ OK ]$ sudo iptables -L -n | grep 'tcp.*59' ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:5901netstat -tnlp
ログ
その他
第411回 VNCサーバー/クライアントを使用してみる
http://gihyo.jp/admin/serial/01/ubuntu-recipe/0411https://www.tecmint.com/install-and-configure-vnc-server-in-centos-7/
- 投稿日:2019-06-22T08:07:12+09:00
flaskアプリを、pdbを活用してデバッグする
手順
stack overflowのDebugging flask with pdbを参考にしています。
screenなどを使って2つ端末を立ち上げておきます。以降端末1、端末2と書きます。
flaskアプリ上のデバッグを開始したい箇所に、次のコードを埋め込みます。
import pdb; pdb.set_trace()端末1で、flaskのdevelopment用サーバをflask runにて起動します。下のようにFLASK_ENVを設定するとデバッグ出力モードになります。(参考:flask Development Server)
$ export FLASK_ENV=development $ flask runこの状態のまま、端末2で、curlコマンドで該当のアプリにアクセスします。
なお、curlの使い方は「curlコマンドの使い方 ~GET、POST、REST(json)の確認と、windowsでの利用手順」が分かりやすく参考になりました。そうすると、端末2(curl側)では待機状態になっているはずです。このまま端末1(flask側)を見るとpdbに入っていますので、後は端末1側でpdbにてデバッグすることができます。
環境
次でできました。難しい仕組みを使っていないので、広く活用できると思います。
flask: 1.0.2
python: 3.7.3
サーバ側のOS: linux(CentOS7)最後に
pdbはシンプルで便利なので、flaskアプリでもpdbでデバッグができて幸せでした。
- 投稿日:2019-06-22T08:07:12+09:00
flaskアプリを、pdbを活用してデバッグする方法
手順
stack overflowのDebugging flask with pdbを参考にしています。
screenなどを使って2つ端末を立ち上げておきます。以降端末1、端末2と書きます。
flaskアプリ上のデバッグを開始したい箇所に、次のコードを埋め込みます。
import pdb; pdb.set_trace()端末1で、flaskのdevelopment用サーバをflask runにて起動します。下のようにFLASK_ENVを設定するとデバッグ出力モードになります。(参考:flask Development Server)
$ export FLASK_ENV=development $ flask runこの状態のまま、端末2で、curlコマンドで該当のアプリにアクセスします。
なお、curlの使い方は「curlコマンドの使い方 ~GET、POST、REST(json)の確認と、windowsでの利用手順」が分かりやすく参考になりました。そうすると、端末2(curl側)では待機状態になっているはずです。このまま端末1(flask側)を見るとpdbに入っていますので、後は端末1側でpdbにてデバッグすることができます。
環境
次でできました。難しい仕組みを使っていないので、広く活用できると思います。
flask: 1.0.2
python: 3.7.3
サーバ側のOS: linux(CentOS7)最後に
pdbはシンプルで便利なので、flaskアプリでもpdbでデバッグができて幸せでした。
- 投稿日:2019-06-22T05:35:08+09:00
(No.12) おじさんが、LINE風アプリを開発する - Apache HTTP ServerをDockerで起動してみる(その1)
前回までのあらすじ
- GitHubを利用して、おじさんの成果物を公開する準備が整いつつあるよ
- 目標を立てたよ、LINE風アプリが作れるようになることを目指すよ
- 開発環境の差異を軽減することが出来ないか考えてみるよ
- Webサーバを構築してみるよ
今回やること
- Webサーバの一つであるApache HTTP Serverの起動にチャレンジしてみる。
Dockerのおさらい(おじさんの理解)
- Dockerfileを作成する。
- アプリを動作させる環境がどのようなものか、どのようなアプリを起動するのかについて書く。
- Linuxディストリビューション(Dockerの場合、Linuxカーネル以外のOSを構成するプログラムの集合を指す)を含むベースイメージを元に作成する。
- おじさんの場合はベースイメージにAmazon Linux 2を選択したよ。
- Dockerfileからイメージを作成する。
- イメージからコンテナを作成&起動する。
Apache HTTPD Serverのインストール
1. 公式サイトの手順を調べる(http://httpd.apache.org/)
- 公式サイトのインストール手順
- スマホのアプリのように、ダウンロードしてインストール完了といった単純な方法が書かれていないよ。
- インストーラの代わりに、Apache HTTPD Serverのプログラムコードが公開されているよ。
- プログラムコードのことをソースコードとも呼ぶらしいよ。以後、おじさんはソースコードと呼ぶことにするよ。
- 何やらコンパイルと呼ぶ作業?が必要みたい。
1-1. コンパイルって何だろう・・・
- よくわからないからおじさん頑張って調べてみたよ。
- Apache HTTPD Serverの場合、ソースコード(プログラムコード)は、C言語と呼ばれる種類の表現方法で書かれていることがわかったよ。
- macOS、Windows、LinuxなどのOSは、ソースコードのままではアプリとして実行することが出来ないみたいだよ・・・。
- ソースコード(プログラムコード)をコンピュータに与えれば、コンピュータは指示通りに動くものだと思っていたよ・・・。
- ソースコードを元に、アプリとして実行するには次の手順が必要みたいだよ。
- (1) ソースコードをダウンロードする。(Apache HTTPD Serverのソースコードはここにあるよ)
- (2) ソースコードをOSが求める仕様通りの形式に変換・翻訳・整形する。
- (3) オブジェクトファイルや、その他、誰かが作成した別のオブジェクトファイル(再利用可能なプログラムの部品をライブラリと呼ぶらしいよ)を、合体させたり、OSが求める仕様通りの形式に整形する。
- (4) リンカによって作成されたアプリは、その内容をメインメモリに読み込むことで、アプリとして起動することが可能になるみたいだよ。
- アプリをメインメモリに展開するソフトウェアを、ローダと呼ぶみたいだよ。
- ここまでの調査で、コンパイルとは、ソースコードをOSが理解出来る形式に変換・翻訳する行為だと理解したよ。
- Apache HTTP Serverの公式サイトに書かれている「コンパイル」とは、コンパイルとリンクの2つの作業を総称していることがわかったよ。
要するに、ソースコードから、OS上で実行可能なアプリに変換・翻訳・整形する手順が書かれていたことがわかったよ。
おじさんはプログラムのこと、まだよくわからないんだけど、ネットに落ちている情報をみると、おじさんのmacOSでもC言語をコンパイルすることができるみたいなんだ。
前記の内容がいまいち実感できないから、簡単なC言語のプログラムを書いて、前記の図の流れを追体験してみたよ。
- 注意: 事前にApple Storeから、Xcodeというアプリをインストールしておかないと出来ない作業みたいだよ。
C言語のプログラムをVS Codeなどで、「main.c」というファイル名で下記の通り書いてみたよ。(おじさんも書いている内容の意味はわからないけど、Hello って文字を表示するだけのプログラムみたいだよ。)
#include <stdio.h> int main(int argc, char *argv[]) { printf("Hello\n"); return 0; }
- 続いて、ターミナルを開いて、main.cの保存先(おじさんの場合は/Users/oyaji以下に保存したよ)に作業するディレクトリを移動するよ。
cd /Users/oyaji
- 続いて、プリプロセッサを試してみるよ。 macOSの環境では「gcc」と呼ばれるコマンドを利用することで試すことが出来るよ。
gcc -E main.c
- すると、ぐちゃぐちゃ〜っと、プログラムコードのようなものが表示されるよ。長いから省略するけど、これが前処理(プリプロセス)したC言語のソースコードだよ。
- #include(何かはおじさんもまだわからないけど)という記述が消えて、代わりにプログラムっぽい何かに置き換えられているよ・・・。
- どうも、人間のために便利な表現がC言語は可能のようだけど、それを、コンピュータにとって都合の良い形に展開?整形?した結果のようだよ。
// 〜 中略 〜 int printf(const char * restrict, ...) __attribute__((__format__ (__printf__, 1, 2))); int putc(int, FILE *); int putchar(int); // 〜 中略 〜 int main(int argc, char *argv[]) { printf("Hello\n"); return 0; }
- プリプロセッサの仕事が何かは、実際にC言語をやってみないとよくわからなさそうだね。
- 続いて、コンパイルを試してみるよ。 ターミナル上で次のコマンドを入力するとC言語のソースコードが、アセンブリ言語のソースコードに変換されるよ。
gcc -S main.c
- 実行すると、main.cと同じディレクトリ内にmain.sというファイルが作られているよ。これがアセンブリ言語に変換した結果だよ。
.section __TEXT,__text,regular,pure_instructions .build_version macos, 10, 14 sdk_version 10, 14 .globl _main ## -- Begin function main .p2align 4, 0x90 _main: ## @main .cfi_startproc ## %bb.0: pushq %rbp .cfi_def_cfa_offset 16 .cfi_offset %rbp, -16 movq %rsp, %rbp .cfi_def_cfa_register %rbp subq $32, %rsp movl $0, -4(%rbp) movl %edi, -8(%rbp) movq %rsi, -16(%rbp) leaq L_.str(%rip), %rdi movb $0, %al callq _printf xorl %ecx, %ecx movl %eax, -20(%rbp) ## 4-byte Spill movl %ecx, %eax addq $32, %rsp popq %rbp retq .cfi_endproc ## -- End function .section __TEXT,__cstring,cstring_literals L_.str: ## @.str .asciz "Hello\n" .subsections_via_symbols
- 何書いているか、だんだんよくわからなくなってきたね。でも、アセンブリ言語も人間のためのプログラミング言語らしいよ。
- アセンブリ言語の状態ではコンピュータは理解することが出来ないらしいよ。続いて、アセンブリ言語(main.s)から、コンピュータが理解可能なマシン語に翻訳してみるよ。
- ターミナルで引き続き次のコマンドを実行すると、アセンブルが実行されるよ。
as -o main.o main.s
- 成功すると、main.sと同じディレクトリに、main.o(オブジェクトファイル)が出来上がってるよ。
- この状態だと、アプリを実行するために必要なパーツ(ライブラリ)や、OSが期待する形になってないみたいだよ。
- 続いて、次のコマンドでリンクしてみるよ。(本当はldというリンカが使われるのだけど、指定するパラメータが複雑なのでgccを使うよ)
gcc -v -o main main.o
- 実行結果が表示されるよ。(-vをつけているので) 「ld」というリンカが使われていることがわかるよ。
Apple LLVM version 10.0.1 (clang-1001.0.46.4) Target: x86_64-apple-darwin18.6.0 Thread model: posix InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld" -demangle -lto_library /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/libLTO.dylib -dynamic -arch x86_64 -macosx_version_min 10.14.0 -syslibroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk -o main main.o -L/usr/local/lib -lSystem /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/10.0.1/lib/darwin/libclang_rt.osx.a
- リンク後のファイルは、main.oと同じディレクトリ内に「main」というファイルで作成されているよ。
- 次のコマンドで、試しにターミナル上で「main」を実行してみるよ。
./main
- 実行結果だよ。ターミナル上に「Hello」と表示されたよ。
- なんだか、文字を表示するだけでも、大変なことが起きてるんだね。
- C言語が何かよくわからないけど、C言語で書かれたソースコードから、実行可能なアプリになるまでを試すことが出来たよ・・・。
1-2. コンパイルの調査で、おじさんにとって衝撃的だったこと
- ソースコード(プログラムコード)は、機械のために存在すると、おじさんは考えていたけど、むしろ人間のために存在するという事実に驚いたよ。
- ABIに準拠するファイル形式は、2進数(0と1の2値)の羅列で構成されているようなので、人間が手作業で作成するのは非効率みたいなんだ。
- Apache HTTPD Serverの場合は、C言語?と呼ばれる種類のソースコードで開発されているみたいだけど、それは開発効率を改善するためだって理解したよ。
1-3. 実行可能なアプリの状態で配布しないのはなぜだろう・・・
- おじさんは未確認だけど、Windows用のインストーラは用意してくれているみたいだよ。
- 前記の通り、OSが求めるアプリの形式は、OSの種類やCPUによって異なるみたいなんだ。Linuxだけをみても、複数の種類が存在するので、全ての環境に最適なアプリの形で配布するというのは無理がありそうだよ・・・。
- ソースコードだけを提供して、実行する環境毎に最適なアプリを作成出来るようにした方が効率は良さそうだよね。(本当の理由はおじさんにはわからないけどね)
1-4. もう少し簡単そうな方法を調べてみるよ・・・
- 実際にコンパイルとやらを試してみるべきかもだけど、それは別の機会に試すことにするよ。(むしろ試した方が楽しそうだけど・・・)
- ちょっと切り口を変えて、Amazonの公式サイトにApache HTTPD Serverのインストール手順が存在するか確認してみるよ。(ベースイメージにAmazon Linux 2を選択していたことを思い出したよ)
2. AWS(Amazon Web Services)の手順を調べる
- Dockerの例ではなかったけれど、AWSが提供するクラウドコンピュータ上にApache HTTPD Serverをインストールする手順があったよ。
- Amazon Linux 2には、「yum」と呼ばれるインストーラが含まれるみたい!! うれしい。
- yumは、あらかじめソースコードからアプリの形式に変換・翻訳済みのファイルを、インストールしてくれるソフトウェアのようだよ。
- インストールだけではなく、インストール済みのソフトウェアのアップデートにも対応してくれるものみたい。
- macOSのApp Storeや、Windows Updateのようなものなのかな。
- ということで、おじさん、AWS上の手順を一度試してみることにするよ。
2-1. Dockerfileを書く前に・・・
- 調べて→Dockerfileに書いて→イメージファイルを作成して→起動して・・・を繰り返せばいつか成功すると思うけど、なんだか効率が悪そうだよ。一発で成功するとは思えないし・・・。
- コンテナ内で直接インストール作業を試すことも出来るみたいだから、次の作業順でチャレンジしてみるよ。
- はじめにコンテナ内で直接インストール作業を試す。 試行錯誤する。
- インストール作業に成功すれば、その作業をDockerfileに書く。
- Dockerfileからイメージファイルを作成する。
- イメージファイルから好きなときにWebサーバを起動することが出来るようになる。ハッピー。
2-2. Amazon Linux 2のベースイメージからコンテナを作成&起動&試行錯誤する準備
docker imagesで、作成済み or ダウンロード済みのイメージ一覧を取得する。
docker images一覧のIMAGE IDをみると、「b94321659aca」に該当するイメージが、ベースイメージのAmazon Linux 2であることがわかるよ。
REPOSITORY TAG IMAGE ID CREATED SIZE ojisanimg1 1.0 826623e781ef 19 hours ago 375MB amazonlinux 2.0.20190508 b94321659aca 3 weeks ago 162MBもしも、docker imagesで、amazonlinuxが見当たらない場合は、(No.10) おじさんが、LINE風アプリを開発する - Dockerを使用してコンテナを作成&実行してみるを実施するか、次のコマンドでベースイメージをダウンロードすることが出来るよ。
docker pull amazonlinux:2.0.20190508引き続き、次のコマンドで、ベースイメージを元にコンテナを作成&起動して、起動したコンテナ内をmacOSのターミナルから操作することが出来るようになるよ。
「b94321659aca」は、前記の「docker images」で確認したイメージIDだよ。docker run -i -t --rm b94321659aca /bin/bashすると、次のように表示されるよ。一見するとよくわからないけど、コンテナ内でコマンドを実行することが出来る状態なんだよ。
bash-4.2#試しに、OSの名前を表示するコマンド uname を実行してみるよ。
bash-4.2# uname -a Linux aeaab6158a92 4.9.125-linuxkit #1 SMP Fri Sep 7 08:20:28 UTC 2018 x86_64 x86_64 x86_64 GNU/Linuxわおっ。Linuxと表示されているよ!! おじさんはmacOS上で実行しているから、明らかにmacOSではなくて、別のどこか(コンテナだよ)で実行されたことがわかる結果だね。
コンテナ内の作業をやめるときは、exitコマンドを実行すれば良いみたいだよ。
bash-4.2# exit
「docker run」コマンドで、何やらコンテナ内でコマンドを実行出来るようになったみたいだけど、どういうことかイマイチおじさんわからないよ。
おじさんは子供のときから「説明の出来ないことはやるな」って親に言われて育ってきたから、よくわからないことは、これからひとつずつ解決していくよ。
(でもいま思ったんだけど、誰でもはじめは説明出来ないよね。実際に調べたり手を動かして試してみないとさ。)うーん。おじさんにはわけのわからない言葉が並んでるよ。つらいね。
docker runのパラメータ 解説 -i 標準入力を開いたままにする。 -t pseudo-tty(疑似端末)を割り当てる。 --rm --rmを指定すると、コンテナの停止後、停止したコンテナが自動的に削除されるようになる。(通常は、docker runを実行する都度、コンテナは新規に作成され、コンテナの停止後も、コンテナ自体は残り続ける。実験中は--rmをつけておくと便利。) b94321659aca 「docker images」で確認したイメージIDだよ。(イメージIDは開発環境によって異なるよ) /bin/bash コンテナ内のAmazon Linux 2に付属する、Bashと呼ばれるシェルを実行する。 2-2-1. 標準入力、擬似端末、シェルって何?!
- docker runのパラメータの意味を理解するには、「プロセス(Process)」「標準入出力(Standard streams)」「制御端末(tty)」「擬似端末(pseudo-tty/pty)」「シェル(shell)」の存在を理解する必要があるみたいだよ。
- なんだか本格的になってきたね・・・。おじさん不安でたまらないよ。
2-2-2. docker runと、Docker daemonと、コンテナの関係
- 概要はここに書いてあったよ。
- ここでおじさんが言いたいことは、macOSから直接、コンテナの中身をいじくり回すことなんて出来ないよってことが言いたいんだよ。(でも実際はコンテナ内にアクセスすることが出来たっぽいよね)
- docker runのやっていることは、指定するイメージファイルからコンテナを作成&起動するように、Docker daemonに対して、指示を送ることであって、docker run自体がコンテナを作成&起動することはないみたいだよ。
- イメージやコンテナの管理はDocker daemonの仕事なので、おじさんのmacOSから、コンテナの中へアクセスするには、「docker run」↔「Docker daemon」↔「コンテナ」と、中継する必要があるみたいなの。
- Docker daemonと、docker runを実行するコンピュータは、同じコンピュータとは限らない。
- そもそも、Docker Desktop for Macのように、Docker daemonは仮想マシン(の上で動作するLinux)上で動作していたり、または、どこか別の場所に設定されたコンピュータ上で動作しているかもしれないんだ。この点からも、docker runのようにdockerコマンドを介して、間接的にコンテナとやりとりする必要があると言えるよ。
2-2-3. ターミナル起動〜docker runで、コンテナ内でコマンドを実行するまでの出来事
「docker run」コマンドはターミナルアプリ経由で実行しているよね。
ところがおじさんは、ターミナルがそもそも何者なのかよくわかってないんだよね。
docker runが実行されるまでの流れを、おじさんなりに調べてみたよ。(おじさんは勉強中だから、嘘が書いているかもしれないよ)ターミナルアプリが何者かわからないけど、macOSで動作するアプリ。だから、前記のように、コンパイル?されるなどして、作られたものであることは間違いないと思うよ。
と、それはさておき、ターミナルアプリのアイコンをクリックすると、黒い画面が表示されるよ。こんな感じでターミナルアプリが起動する。
macOSのターミナルアプリをwikipediaで調べてみると、ターミナルアプリは「端末エミュレータ(terminal emulator)」であると書かれているよ。
続いて、端末エミュレータをwikipediaで調べてみると、端末エミュレータはコンピュータプログラムであり、端末(terminal)を再現(エミュレート)したものと書いてあるよ。
そもそも端末(terminal)がよくわからないので、さらにwikipediaで調べてみたよ。ここから先はおじさんの理解を書いていくよ。
macOSやLinux、UnixといったOSは、1台のコンピュータ(下図、右側のサーバと書かれている箱)を複数人に共有することが出来るみたいなんだけど、
複数人に1台のコンピュータを共有するシチュエーションで、端末エミュレータなるものが必要になるっぽいんだよ。(おじさん、絵心がなくて泣けて来るよ・・・)AさんとBさんは、インターネットを経由して、遠隔地にあるサーバに接続して、遠隔操作することを考えてみるよ。
この場合、AさんとBさんの手元にはそれぞれ、ディスプレイやキーボードがあるけれど、遠隔地のサーバ側には、接続する人の数分のキーボードもディスプレイも接続されているわけじゃないんだ。
それでも、AさんやBさんのディスプレイやキーボードが、あたかもサーバ側に物理的に接続されているかのように、振る舞う仕組みを端末エミュレータを介して実現しているみたいだよ。(詳細は徐々に明らかにしていくよ)
このような仕組みがあるおかげで、遠隔で操作されるプログラムからすれば、物理的なキーボードで操作されているのか、それとも遠隔接続で操作されているのかを意識する必要がなくなるみたいだよ。なんだか賢いね。続いて疑問になるのが、おじさんのmacOS自体は、おじさんの手に届くところにあるのに、なぜ端末エミュレータなんか使わなきゃならないのかってことだよ。
遠隔操作じゃないのね。
でも、ターミナルを複数起動すると、なんだか納得出来るものがあるよ。ターミナルのウィンドウそれぞれが、独立して動作して、それぞれ異なるプログラムを動作させることが出来るようになっているよ。
つまり、1台のMacの中に、1つの接続というわけではなくて、Aさん・Bさんの例のように、ウィンドウの数だけ独立した接続が必要になるってことなんだ。
だから自分自身のコンピュータであったとしても、端末エミュレータが必要になるみたいだよ。実際にはここまで単純ではないけれど、端末エミュレータの必要性を説明するための抽象画だと思ってほしいよ。
もう少し深掘りしていくよ。
結論を書くと端末エミュレータ自体は、シェル(Shell)と呼ばれるプログラムを(間接的に)起動して、疑似端末と呼ばれる特殊なファイルの内容を読み書きしているだけのようなんだ。 何を言っているのか、おじさんにもよくわからなくなってきたから、少しずつ整理していくよ。と、深掘りするまえに、プロセスとは何か、標準入出力とは何かを知っておく必要があるみたいだよ。
まずはプロセスから。
アプリは起動すると、「プロセス」と呼ばれるアプリが起動した状態になるらしいよ。
例えば、WindowsのExcelやWordみたいなアプリって、複数立ち上げると、それぞれのワークブックごとに内容が異なるよね。 この例のように、同じアプリであっても起動後のアプリの状態(Excelのワークブック)は異なるように、実行中のアプリの状態を表現する単位みたいだよ。下図はWindowsでExcelのプロセスが5つ動作しているイメージだよ。(Windowsを例にしているのは、macOSの場合だと、一つのアプリは一つのプロセスでしか動作しないからだよ。macOS版のExcelを例にすると、ワークブックをいくら開こうが、Excelのプロセスは一つだけだよ。)
ここまでで、アプリ(プログラム)は、実行中になると「プロセス」と呼ばれる状態になるってことがわかったよ。
プロセスは、プロセス同士で通信する手段・方法が様々用意されているみたいだよ。
プロセス同士の通信を、プロセス間通信(IPC)と呼ぶらしいよ。プロセス間通信の内容によっては、アプリ側であらかじめ考慮しておく必要があるけれど、標準で用意されているデータの伝送手段があって、この標準的な伝送手段を標準入出力と呼ぶみたいだよ。
標準入出力は、起動したプロセスに標準的に与えられるデータの伝送手段で、入力側も出力側も共に何かしらのファイルに関連付けられているみたいだよ。実験のため、次のコマンドを試してみるよ。
echo oyaji
こんな感じで、ターミナルに「oyaji」と表示されるだけだよ。
echoコマンドのマニュアルを表示して意味を確認してみるよ。マニュアルを表示するには「man」コマンドを使えば良いよ。
man echo
すると、次のようにマニュアルが表示されるよ。(終了するには、「q」アルファベットのキューを入力)
マニュアルには「標準出力(standard output)に引数を書き込む」旨が書かれているよ。
この場合の引数とは、「oyaji」にあたる部分だよ、つまり、echoコマンドのパラメータのことだよ。echoコマンドも例外ではなく、実行中はプロセスとして動作するよ。
再び、echoコマンドのマニュアルに書いてあった「標準出力(standard output)に引数を書き込む」が重要になってくるよ。
「echo oyaji」を実行すると、「oyaji」の文字が標準出力に書き込まれるみたい。
でも実際はターミナルのウィンドウに「oyaji」と出力(表示)されたよ。これは、ターミナルのプロセスと、echoコマンドの標準出力との間に何かしらの関係があることを示唆するものだよ。この謎を解き明かすためには、macOSやLinux、UnixといったOSの基本原理である「デバイスファイル(スペシャルファイル」についても知っておく必要があるよ。
話がややこしくなってきたので、箸休めに、おじさんの書いた猫の絵で癒やされてほしいよ。
どうだろう。癒やされたかな。
次はデバイスファイル(スペシャルファイル)についてだよ。Unixと呼ばれるOS(や、Unix系OSと呼ばれるLinuxなど)では、Everything is a fileといった設計思想があるらしくて、ありとあらゆるものをファイル(ただしくは、ファイルディスクリプタ)で表現しようという考えみたいだよ。
この設計思想のおかげで、入出力といったデータの流れのあるものをファイルという統一された方法で操作出来るようになるみたい。例えば、CDやDVDのような機器の操作から、インターネットなどのネットワーク処理(socket)すらも、Unix系のOSでは、ファイル(ファイルディスクリプタ)として扱うようなんだ。
このような特殊なファイルをデバイスファイル(またはスペシャルファイル)と呼ぶみたいだよ。ここで言いたいのは、macOSやLinux、Unix上での「ファイル」とは、おじさんのポエムのようなテキストファイルだけではなくて、ハードウェア(CDやDVD、キーボードやディスプレイなど)やネットワークなどの、入出力といったデータの流れのあるものを指すこともあるってことなんだよ。
おじさんが使っているmacOSでも同じことが言えるんだよ。
ここまでを整理すると次の情報が手に入ったよ。
- アプリは起動するとプロセスと呼ばれる状態となってプログラムが実行されるよ。
- プロセスには、アプリが意識していなくても、プロセスへのデータの通信経路が作成され、これを標準入出力と呼ぶ。
- 標準入出力は、データの流れを表すもので、データの入力元に何かしらのファイル、データの出力先にも何かしらのファイルが関連付けられているよ。
- アプリ(プロセス)からすれば、標準入出力の元・先が何であるのかを知る必要はないみたいだよ。
- Unix系OSでは、データの入出力といったデータの流れをファイル(ファイルディスクリプタ)で表現しているよ。macOSも同様だよ。
- おじさんのポエムのようなファイルとは別に、例えば、ディスプレイやキーボード、ネットワークといった機器もファイル(ファイルディスクリプタ)で表現されている。このような特殊なファイルをデバイスファイル(またはスペシャルファイル)と呼ぶみたいだよ。
これらの情報を元に、ターミナルが起動して、echoコマンドを実行するまでの出来事を詳細に解説してみるよ。
まずターミナルアプリがユーザの操作をきっかけに実行されるよ。当然、ターミナルアプリもプロセスとして実行するよ。
ターミナルプロセスがopenシステムコールなどを使用して、「/dev/ptmx」(擬似端末)のデバイスファイル(スペシャルファイル)にアクセス。
すると、擬似端末のマスタとスレーブのペアが作成される。(このファイルが何者かは後述)
以降、擬似端末のことをpty(マスタ)、pty(スレーブ)と書く。続いて、ターミナルプロセスがforkシステムコールを実行する。forkシステムコールを実行すると、実行元プロセスの写しが作成される。(プログラムの実行状態なども含め複製される)
ターミナルプロセス(写し)が、dup2システムコールを実行し、ターミナルプロセス(写し)の標準入出力先をpty(スレーブ)に変更する。
ターミナルプロセス(写し)が、execシステムコールを実行し、loginコマンドのプロセスにターミナルプロセス(写し)を置き換える。
loginプロセスに置き換え後も、標準入出力先はpty(スレーブ)に維持される。(ファイルディスクリプタの状態はfork/exec後も維持されるため)
loginプロセスはログインユーザ固有の設定(例えば、作業ディレクトリをホームディレクトリに変更する)などを行い、forkシステムコールを実行する。loginプロセスの複製が作成される。
loginプロセス(写し)は、execシステムコールを実行して、loginプロセス(写し)をbashプロセスに置き換える。
loginプロセス(写しではない)は、closeシステムコールを実行して標準入出力を閉じる。(この時点でloginプロセスの仕事は何もないため)bashプロセスが起動する。なお、bashプロセスはシェルと呼ばれるプログラム。
ターミナルプロセスに対して、「echo oyaji」と入力すると、ターミナルプロセスはpty(マスタ)に「echo oyaji」と書き込みする。
pty(マスタ)に書き込みした内容は、pty(スレーブ)の先の標準入力に流れ込むため、bashプロセス側で「echo oyaji」の入力を取り出すことが出来る。
ターミナルからの入力を間接的に受け取った後、bashプロセスはforkシステムコールを実行する。
- pty(マスタ)とpty(スレーブ)はつながっている。
- pty(マスタ)に書き込むデータは、pty(スレーブ)から読み取ることが出来る。
- pty(スレーブ)に書き込むデータは、pty(マスタ)から読み取ることが出来る。
- pty(擬似端末)は、プロセス間通信の手段の一つと言える。
bashのプロセスが複製される。
bashプロセス(写し)が、execシステムコールを実行して、bashプロセス(写し)をechoプロセスに置き換える。
echoプロセスも複製元のbashプロセスと同様に、標準入出力先はpty(スレーブ)に設定されている。echoプロセスは、コマンドの引数(パラメータ)に与えられた内容を標準出力に書き込む処理を実行する。
引数の値は「oyaji」なので、標準出力に「oyaji」を書き込む。
標準出力先はpty(スレーブ)のため、結果的にpty(マスタ)の入力に「oyaji」のデータが流れる。
ターミナルプロセスはpty(マスタ)から、pty(スレーブ)の書き込みを取り出して、ターミナルウィンドウに出力する。
echoプロセスは仕事を終えたため、プロセスを終了する。その結果こうなる。
ここまでの情報を整理をしてみるよ。
- pty(擬似端末)を使用して、プロセス間(ターミナル〜bashやbash以降のプロセス)のデータの受け渡しを実現している。
- ターミナルはpty(疑似端末)のマスタに対して流れてくるデータを表示、キーボードからの入力を、pty(疑似端末)のマスタに書き込む。
- ターミナルはforkシステムコールを使用して、自身のプロセスを複製する。
- 複製したプロセスの標準入出力先をpty(スレーブ)に設定する。なお、pty(スレーブ)の名前を取得するには、ptsnameシステムコールを使用する。
- 複製したプロセスから、execシステムコールを実行して、複製したプロセスをloginプロセスに置き換える。
- なぜforkとexecが別れているのか考えてみると面白いと思うよ。
- なぜわざわざ、プロセスを複製してから、目的のプログラムのプロセスに置き換えるように設計されているのか。
- こんな言葉があるよ。
- loginプロセスでは、ログインユーザ固有の設定(例えば、作業ディレクトリをユーザのホームディレクトリに設定する)など実行した後に、forkシステムコールを実行する。
- loginプロセス(写し)では、execシステムコールを実行し、loginプロセス(写し)をbashプロセスに置き換える。
- bashプロセスでは、fork&execで、プロセス複製後にechoプロセスに置き換える。
- echoプロセスは標準出力に書き込みする。標準出力先はpty(スレーブ)のため、ターミナルが監視するpty(マスタ)に伝わり、ターミナルの画面上にechoプロセスが書き込む内容が出力される。
いまいち、擬似端末(pty)の実感が沸かないと思うんだけど、簡単に試すことが出来るよ。
下図はターミナルを2つ起動してみた例だよ。
ttyコマンドを実行することで、標準入力に設定されているpty(スレーブ)を確認することが出来るよ。tty
すると、それぞれのターミナルに異なる内容の文字が表示されるはずだよ。
おじさんの場合は、「/dev/ttys000」と「/dev/ttys001」とそれぞれ表示されたよ。
「/dev/ttys000」と「/dev/ttys001」それぞれが、pty(スレーブ)のファイルを表しているよ。このような特殊なファイルをデバイスファイル(スペシャルファイル)と呼ぶらしいよ。
ターミナルのウィンドウそれぞれに、pty(マスタ)・pty(スレーブ)のペアが設定されていることがわかるよ。試しに、ターミナルのウィンドウそれぞれに表示されているpty(スレーブ)に対して書き込みしてみるよ。
次のコマンドを実行すると、/dev/ttys001に対して、helloという文字を書き込むことになるよ。
echoコマンド自体は引数(hello)の内容を標準出力に書き込むというものだったけど、「>」(リダイレクトと呼ぶ)を書くことで、
標準出力を「/dev/ttys001」に変更することになるよ。(まるでdup2システムコールそのものだね)
なお、「>」リダイレクトや、echoプロセスの起動は、bashプロセス(シェル)が実行していることだよ。echo hello > /dev/ttys001うーん。どんどん理解してきた気がするね。
bashはシェルと呼ばれるプログラムだけど、macOSやLinuxカーネルといったOSと対話するための手段の一つだよ。
シェルはOSが提供する機能(システムコール)を実行して、他のアプリやコマンドを起動したり、簡単なプログラムも実行することが出来るみたいだよ。ついでに、実行中のプロセスを確認する方法もここで書き残しておこうと思うんだ。
次の「ps」コマンドで実行中のプロセスを確認することが出来るよ。ps -eaf
わわっと、動いているプロセスが多すぎて、何がなんだか・・・。
「Terminal」の文言が含まれる行に限定して表示されるように改良してみるよ。
ps -eaf | grep Terminal「|」は、パイプといって、リダイレクトのように標準入出力を変更するものだよ。
psコマンドと、grepコマンドの意味はそれぞれ下図の通りだよ。
この2つのコマンドを、パイプと呼ばれるデバイスファイル(スペシャルファイル)を使って、標準入出力をそれぞれ繋ぎ合わせることで
psコマンドの結果をgrepコマンドでフィルタリングすることが出来るんだよ。実行結果だよ。(注:UID、PIDなどのヘッダは、わかりやすくするために手で追加したものだよ)
UID PID PPID C STIME TTY TIME CMD 501 84232 1 0 5:41PM ?? 0:12.44 /Applications/Utilities/Terminal.app/Contents/MacOS/Terminal 501 93153 84234 0 7:27PM ttys000 0:00.00 grep TerminalPID(プロセスID)列は、プロセスを識別するための固有の番号を表すよ。
この例の場合、PIDが「84232」のプロセスがターミナルアプリのプロセスだよ。
なお、PPID(親プロセスID)列は、fork元の親プロセスのプロセスIDを意味するよ。 PIDが1のプロセスからTerminalが作成されていることがわかるけど、PIDが1のプロセスは特別なプロセスで、initプロセス等と呼ぶことがあるみたいだよ。(はじめに作成されるプロセスだよ)引き続き、ターミナルのプロセスID(84232)で検索してみるよ。
ps -eaf | grep 84232実行結果だよ。 loginプロセスが2つあることに注目だよ。
これはターミナルウィンドウを2つ開いているからだよ。UID PID PPID C STIME TTY TIME CMD 501 84232 1 0 9:48PM ?? 0:30.23 /Applications/Utilities/Terminal.app/Contents/MacOS/Terminal 0 84233 84232 0 9:48PM ttys000 0:00.01 login -pf oyaji 501 93246 84234 0 4:09AM ttys000 0:00.00 grep 84232 0 93137 84232 0 4:05AM ttys001 0:00.02 login -pf oyajiさらに、1つ目のloginプロセスのプロセスIDで検索してみるよ。
ps -eaf | grep 84233結果だよ。 bashプロセスがあるね。
UID PID PPID C STIME TTY TIME CMD 0 84233 84232 0 9:48PM ttys000 0:00.01 login -pf oyaji 501 84234 84233 0 9:48PM ttys000 0:00.10 -bash 501 93302 84234 0 4:11AM ttys000 0:00.00 grep 84233もう片側のloginプロセスも。
ps -eaf | grep 93137やっぱりbashプロセスが存在するね。前記の説明通りプロセスは作成されていることがわかるよ。
プロセスは親子関係(forkするプロセス、forkされたプロセス)があることもわかったよ。UID PID PPID C STIME TTY TIME CMD 501 93351 84234 0 4:13AM ttys000 0:00.00 grep 93137 0 93137 84232 0 4:05AM ttys001 0:00.02 login -pf oyaji 501 93138 93137 0 4:05AM ttys001 0:00.01 -bash長かったけど、docker runのパラメータの意味を理解することが本来の課題だったんだよ。長くて忘れかけていたよ。
こんなコマンドだったよ。docker run -i -t --rm b94321659aca /bin/bash下図がdocker runの全貌だよ。ここまでの情報を集結させて挑むことにするよ。
- docker runの右端にある「/bin/bash」とは、図の中にあるコンテナプロセス内で、どのようなプログラムを実行するのかを指定しているんだよ。この例では、「/bin/bash」なので、「コンテナ内の/binディレクトリのなかにある、bashコマンドを実行する」という意味になるんだよ。
- この指定を別のコマンドに変えるだけで、コンテナ内で実行するコマンドを変更することが出来るよ。
- 「-t」は、docker runの実行元で、コンテナプロセス内の標準入出力を中継出来るように、擬似端末(pty)を作成することを指示するものなんだよ。(Docker daemonが動作するLinux上で擬似端末を作るように指示)
- 「-i」は、ターミナルからの入力をコンテナ側に伝搬することが出来るように、Linux側の標準入力を有効にする設定のようだよ。
- 「-rm」は、コンテナ終了後に、コンテナを削除するように指示するものだよ。(ゴミコンテナが残らないように)
- docker(run)と、Docker daemonは、それぞれ異なるコンピュータ上で動作する可能性があるので、ネットワークやインターネットを経由して送受信する必要があるんだ。おじさんも今はよくわからないけど、ソケットと呼ばれる通信方法で実現しているみたいだよ。
あとがき
うへーーー。おじさんちょっと疲れたよ。前準備だけでこんなに大変だと思わなかったよ〜。
でも何でも積み重ねだから、徐々に楽になっていくことを期待するよ。
次回は、コンテナ内をこねくりまわして、Apache HTTP Serverを何がなんでもインストールしてみるよ。そうそう忘れてた。
macOSのloginコマンドなどのプログラムは、ソースコード(Libsystem-1252.200.5)にて公開されているよ。(C言語で書かれているみたいだよ)
コンパイルする方法もどこかに書かれていることだろうから、コマンドを改造してみるのも面白いかもしれないね。
ターミナルアプリのソースコードが見当たらなかったので、ターミナル周辺に関しては状況証拠や他のターミナルのプログラムを参考に勉強してみたよ。参照・メモ