- 投稿日:2020-12-07T23:33:44+09:00
linux関係自習メモ
・dockerのcentosコンテナで作業した
・入力中のディレクトリやコマンドはtabで補完できる
・深いディレクトリを一気に使う場合はmkdir に-p オプションを付ける
・ディレクトリをコピーしたい場合にはcopyに-rオプションを付ける
・lessコマンドは無かったので、yum install less した
・作る
フォルダ:mkdir
ファイル:touch
- 投稿日:2020-12-07T22:03:11+09:00
Linux netstat
【Linux netstat】
CentOS 7 以降では、netstatは非推奨であり、ss(socket statistics)が推奨。
netstatとssに大きな違いはない。netstatコマンド
TCP/IP関連のトラブルシューティング
主にTCPの通信状態を調べる。
UDPのサービスポートやUNIXドメインソケットの状態、ルーティング情報なども調べる。netstatのオプション
-a (--all) すべてのプロトコルを表示 -l (--listening) 接続待ちのソケットを表示 -n (--numeric) ホスト、ポート、ユーザなど名前を解決せず、数字のアドレスで表示 -p (--program) ソケット、ポートをオープンしているプログラムのPIDと名前を表示 -r (--route) ルーティングテーブルを表示 -s (--statistics) 統計情報を表示 -t (--tcp) TCPソケットを表示 -u (--udp) UDPソケットを表示 -x (--unix) UNIXソケットを表示 ※オプションなしは、TCPポートのLISTEN以外のESTABLISHEDなどの状態とUNIXドメインソケットの状態を表示
- 投稿日:2020-12-07T19:13:05+09:00
UNIX と Linux
UNIX(ユニックス) と Linux(リナックス) はどちらも
OS
の一つです。
CUI ( コマンド入力 ) をメイン操作として動き、背景色が大体黒なので使ってるとエンジニアっぽく見えるやつ。UNIX
UNIXとは最も古参なOSになります。もともとは『Multics』というOSからの派生。
Multicsがあれこれやろうとして複雑怪奇になっていく中で、もっと簡単に出来ねぇもんかと
考えられ生み出されたOS。結果、軽くて機能も少ない上に使い易いとして生まれたので大人気。破格の値段で買える上に UNIXの作り方もついていた為、あれよあれよと広まって色々な形の UNIXが誕生して行くことに.....
鉄人28号が ∀ガンダムになったくらいに派生した所で UNIXとしてのまとまりが無くなって来ている事と、まだシェアはあるから金になるだろうと考え AT&T社が「うちから出すのが本物、使いたいなら金払え」 と言い出し勢いが弱まる。Linux
LinuxとはUNIX系OSの一つであり、Linuxカーネルを軸として作られているOS。
Linuxカーネルとはリーナス・トルバーズさんが開発したソフトウェアのこと。
このリーナスさん、UNIXを使っていて物足りないなぁと感じたところを改造していた結果
ほぼ自走するレベルまで行ってしまい、なんなら最初から作り直すかとノリで始めてLinux誕生。
UNIXを参考に作られていることからUNIX感はあるけどUNIXではないOSが生まれました。
UNIXをガンダムとするなら、Linuxはエヴァンゲリオンってな感じ。( たぶんきっと.... )
このLinux何がすごいって、リーナスさんがノリで作ったOSを「アドバイス下さい」って公開したところ多くのプログラマー達が「あれも欲しい、これも欲しい、もっと欲しい、もっともっと欲しい」と手を加え続け、わずか2年で実用可能。IBMやHP、インテルなどのプログラマーも参加して企業や政府機関にまで取り入れられて行きました。これからもシェアは伸び続けていくと考えられているとか。ソースが公開されているので、様々な種類のLinuxが誕生しました。そのLinuxの種類の事を『Linuxディストリビュージョン』と言います。
RedHat系
商業用に特化したデストリビュージョン。読みはレッドハット。
RedHat社が出している「RedHatEnterpriseLinux」略してRHEL(レル)がLinuxの商用としては業界のスタンダート。
このRHELは "アップストリームファースト" という考え方(機能修正や追加した物を自社内だけで改良し続けるのでは無く、コミニュティを使って改良、成長させていこうとする考え方)のもと開発を行っているため安心感は抜群です。
RedHat系の有名どころではCentOS
Fedora
などがあります。Debian系
RedHatと並んで人気なのがこのDebian(デビアン)になります。
ボランティアが中心になって開発が進められているため、ユーザーに優しい作りになっています。
「Debian 社会契約」を掲げており天使にラブソングって感じ。
- Debian は 100% フリーソフトウェアであり続けます
- 私たちはフリーソフトウェアコミュニティにお返しをします
- 私たちは問題を隠しません
- 私たちはユーザとフリーソフトウェアを大切にします
- 私たちのフリーソフトウェア基準に合致しない著作物について
パッケージ管理(各種のソフトウェアの導入と削除、そしてソフトウェア同士やライブラリとの依存関係を管理するシステム)にも優れており Linux精神を地で行くLinux。
歴史も古いので様々な派生のディストリビュージョンがある。
![]()
Slackware系
最も古くに存在しているデストリビュージョン
公式に配布されているのが全て『 シンプル イズ ザ ベスト !!!』
弄りたいなら自分でやって勝手に調整してって言う、初学者には優しくない
けれど使えば色々勉強になるから使ってみなよって唆され、使っているうちに自分用に
カスタマイズされてて気づいた時には、もうこれじゃなきゃ嫌ってなる。 コアファンが多い。#中毒性 #「スーパーカブ」みたいなヤツ #沼
参考
https://eng-entrance.com/linux_birth
https://kitsune.blog/linux-summary
https://eng-entrance.com/linux_beginner_distribution#Linux-2
https://www.ibm.com/downloads/cas/VW0PZRBO
- 投稿日:2020-12-07T18:01:29+09:00
Linux認証のためのOpenLDAPをコンテナ(AWS Fargate)で動かす
せっかく作った仕組みですが、使わない方向に進んでいるので供養として投稿。
皆さんはLinuxのユーザ管理はどのように実施されていますでしょうか?
一台一台、温かみのある手作業による管理も良いのですが、流石に令和のこの時代、何らかの方法で一元管理を行いたいものです。EC2 Instance Connect、Systems Manager Session Manager、Teleportなどなど、Linuxへログインするだけであれば、昔から比べると色々な方法が用意されていますが、所属グループの管理やsudo権限の管理なども考え出すと、やはりOpenLDAP + SSSDによる管理がノウハウも豊富で安定しています。
本記事では、Linuxユーザ管理のためのOpenLDAPをAWS Fargate上で稼働させるために私が考えた方法を紹介します。(大枠での挙動に絞って記載し、細かなところは端折っています)
OpenLDAPはコンテナとマッチしない?
いきなりOpenLDAPをコンテナ環境で稼働させてハイ終わりではなく、コンテナ稼働に最適化されたOpenLDAPとはどんなものか、について考えてみます。
一般的に、コンテナ上で稼働させるアプリケーションはImmutableで状態を持たないことが望ましいです。
今回のOpenLDAPであれば、ユーザ情報のような、変更可能性があるようなデータをコンテナ内には持たないような仕組みにしたいです。それでは、状態を持つデータをNFSのようにコンテナ外部に置いておけばOKでしょうか?
困ったことにOpenLDAPのバックエンドとしてよく使われているbdbはNFSのような共有ストレージで使われることは想定されていません。(mdbはどうなんだろう…?)
Can OpenLDAP use NFS to store back-bdb/hdb data?単一のコンテナしか建てられず、ストレージもホストのものを使う、となると果たしてそれはコンテナ化する必要があるのか? という疑問が湧いてきます。
認証はしたいけど認証システムの管理はしたくない
タイトルはOpenLDAPをコンテナで動かしてみたいと思った方へのリーチできるように設定しましたが、実はコンテナでの運用は結果としてそれが最適解となっただけで、最初からOpenLDAPをコンテナで運用する! といったことを目指したわけではありませんでした。
まず、第一にあったのが「認証サーバの運用をしたくない」です。
認証一元管理の仕組み自体はすごく重要ですが、これ自体は企業としての競争優位性を生み出すものではありません。
手間を省くための一元管理の仕組みなのに、その仕組みの管理に手間を取られるのは本末転倒です。
(そして、往々にしてこういったシステムは原因不明のトラブルが起こりがちです……)そこで「認証システム管理の手間を減らすため、OpenLDAPをDisposable/Immutableな環境として運用できないか?」と考えた結果、
「保持するユーザデータを外部で管理して、変更が入るたびに都度コンテナ化してデプロイするのはどうだろう?」と思いつき、その仕組みを設計・構築していきました。処理の流れ
実際にどのような仕組みでOpenLDAPをImmutableなコンテナで稼働させることにしたのか、全体の流れを図にしてみました。
それぞれをステップごとに説明します。
ユーザ情報の管理・変更
ここが従来のOpenLDAP運用と大きく違うポイントです。
ユーザ情報はLDIFファイルをGit(BitBucket)リポジトリで管理しています。
Linuxへのパスワード認証は無効で、公開鍵認証のみでしたので、ユーザ名・UID/GID・公開鍵などは社内限定公開としています。
具体的に管理される情報(LDIFファイル)のサンプルは下記の通りです。
users.ldifdn: cn=hoge.hoge,ou=Users,dc=mydomain,dc=local objectClass: inetOrgPerson objectClass: posixAccount objectClass: ldapPublicKey uid: hoge.hoge uidNumber: 10010 gidNumber: 10000 homeDirectory: /home/hoge.hoge loginShell: /bin/bash mail: hogehoge@hamee.co.jp sn: hoge givenName: hoge gecos: hoge.hoge sshPublicKey: ssh-rsa ***************************************************** dn: cn=foo.bar,ou=Users,dc=mydomain,dc=local objectClass: inetOrgPerson objectClass: posixAccount objectClass: ldapPublicKey uid: foo.bar uidNumber: 10013 gidNumber: 10000 homeDirectory: /home/foo.bar loginShell: /bin/bash mail: foobar@hamee.co.jp sn: foo givenName: bar gecos: foo bar sshPublicKey: ******************************************** sshPublicKey: ********************************************groups.ldifdn: cn=hamee,ou=Groups,dc=mydomain,dc=local objectClass: posixGroup objectClass: top gidNumber: 10000 cn: developer dn: cn=sre,ou=Groups,dc=mydomain,dc=local objectClass: posixGroup objectClass: top gidNumber: 10010 cn: sre memberUid: hoge.hoge memberUid: foo.barsudoers.ldifdn: cn=sre,ou=SUDOers,dc=mydomain,dc=local objectClass: sudoRole objectClass: top cn: sre sudoHost: ALL sudoCommand: ALL sudoOption: !authenticate sudoUser: %sreパスワードなどの本人以外が閲覧可能であるとマズいような情報は含まれていません。
この情報はGitで管理されているため、ユーザがPCのリプレースなどで公開鍵が変更された場合やメールアドレスの変更など、登録上の変更については、自分で変更のためのプルリクを作成することが可能です。所属グループの変更やsudo権限の申請なども、プルリクに申請理由を書く、または別途ワークフローシステムと連携して自動的に作成もできそうです。
作成されたプルリクは承認者によるレビューを経て、適切な権限を持った運用担当者によってマージされます。
OpenLDAPコンテナイメージの生成
運用担当者によるBitBucketでのマージをトリガーにし、BitBucket Pipelineが起動。
LDIFファイルを含むArtifactsをS3にアップロードされS3内アイテムのバージョン変更をトリガーにCodePipeline/CodeBuildが起動します。CodeBuildでは更新されたユーザ情報を含むLDIFファイルを元に、OpneLDAPコンテナイメージを作成しECRにプッシュします。
その後、新たなコンテナイメージはFargateで構成されたECSにデプロイされます。一見、CodePipelineを使用しなくてもBitBucket Pipelineだけですべての処理を完結することができそうです。
なぜCodePipeline/CodeBuildを使用したのか? について説明します。この仕組みでは、ユーザ情報(LDIFファイル)を管理するリポジトリとコンテナイメージを作成するためのDockerfileを管理するリポジトリを分けてあります。
DockerfileのリポジトリにはOpenLDAPの設定ファイルが含まれており、これらのファイルを一般ユーザが閲覧・操作できる場所に置くのは好ましくなかったため、運用者のみにアクセス権が付与されたリポジトリで管理しています。CodePipeline/CodeBuildには複数のソースをトリガにしてビルドを走らせる機能があり、複数のソースのうちどちらかが更新されたらビルドを開始する、という設定が可能です。
AWS CodePipeline を CodeBuild の複数の入力ソースおよび出力アーティファクトと統合するサンプル
ここでは、ユーザ情報が変更された場合・Dockerfileが更新された場合、どちらがトリガーでもコンテナイメージの再作成・デプロイが動くように設定を行いました。
Dockerfileはこのような内容で、
/ldif
ディレクトリに必要なLDIFファイルが配置されている想定で初期化を行っています。DockerfileFROM alpine:latest EXPOSE 636 RUN apk --update --no-cache add openldap-back-mdb openldap openldap-clients openldap-passwd-pbkdf2 RUN mkdir -p /run/openldap && mkdir -p /var/lib/openldap/run && mkdir -p /etc/openldap/slapd.d RUN rm -f /etc/openldap/slapd.conf COPY ldif /ldif COPY slapd.ldif /etc/openldap/slapd.ldif COPY --from=cert-builder /certs /certs RUN slapadd -n0 -F /etc/openldap/slapd.d -l /etc/openldap/slapd.ldif RUN slapd -h ldapi:/// \ && sleep 3 \ && ldapadd -Y EXTERNAL -H ldapi:/// -f /ldif/init/10-domain.ldif \ && ldapadd -Y EXTERNAL -H ldapi:/// -f /ldif/init/20-ou.ldif \ && ldapadd -Y EXTERNAL -H ldapi:/// -f /ldif/groups.ldif \ && ldapadd -Y EXTERNAL -H ldapi:/// -f /ldif/users.ldif -c || true \ && ldapadd -Y EXTERNAL -H ldapi:/// -f /ldif/sudoers.ldif \ && kill -SIGTERM $(pidof slapd) WORKDIR /etc/openldap CMD ["slapd", "-h", "ldap:/// ldaps:///", "-d", "256"]余談ですがこのDockerfileを書いているときに、AlpineLinuxのAportsに登録されているOpenLDAPで、
slapd.ldif
から初期化する処理がうまくいかず、よく見てみると不要な改行が入っていることに気づき修正のプルリクを作成しました。マージされたときはほんのり嬉しかったです
https://github.com/alpinelinux/aports/pull/10225CodeBuildに渡す
buildspec.yml
はこんな感じ。buildspec.ymlversion: 0.2 phases: install: runtime-versions: docker: 18 build: commands: - echo "### mix up each source" - echo "${CODEBUILD_SRC_DIR_SOURCE_LDIF}" - cp -f ${CODEBUILD_SRC_DIR_SOURCE_LDIF}/ldif/*.ldif ${CODEBUILD_SRC_DIR}/ldif/ - echo "### build image" - docker build -t myopenldap:latest ${CODEBUILD_SRC_DIR} - echo "### generate tag" - REPO=************.dkr.ecr.ap-northeast-1.amazonaws.com/myopenldap - LDIF_COMMIT_HASH=$(cat ${CODEBUILD_SRC_DIR_SOURCE_LDIF}/commit-id.txt | cut -c1-7) - DOCKERFILE_COMMIT_HASH=$(cat ${CODEBUILD_SRC_DIR}/commit-id.txt| cut -c1-7) - TAG=${LDIF_COMMIT_HASH}_${DOCKERFILE_COMMIT_HASH} - docker tag myopenldap:latest ${REPO}:${TAG} - echo "### push" - $(aws ecr get-login --no-include-email --region=ap-northeast-1) - docker push ${REPO}:${TAG} # この後はデプロイのためのstepが続くが省略
${CODEBUILD_SRC_DIR_SOURCE_LDIF}
はLDIF管理のリポジトリからのArtifactsが保存されたディレクトリで、${CODEBUILD_SRC_DIR}
はDockerfile管理のリポジトリのものとなります。
つまり、docker build
より前の行でDockerfileリポジトリ内の/ldif
ディレクトリにLDIFリポジトリのLDIFファイルをコピーしています。各リポジトリのbitbucket-pipelines.ymlには
bitbucket-pipelines.yml- echo ${BITBUCKET_COMMIT} > commit-id.txtというステップが定義されていて、コミットIDを
commit-id.txt
というファイルに吐き出してArtifactsに含めるようにしています。
このファイルを元にしてコンテナイメージのタグ名コミットハッシュをつなぎ合わせたユニークな値に設定しています。Fargateへのデプロイ
デプロイはCodeDeployを使用せず、CodeBuild内でecspressoを呼び出しています。
デプロイされたコンテナはNLBのターゲットとして起動し、ヘルスチェックを経てLinuxからのLDAPS/LDAPアクセスを受け取り始めます。
コンテナは別々のAZで2つ以上起動され、一方が何らかの障害で応答不能になったとしても片肺での処理が可能です。ECS Serviceの設定で2つ以上のコンテナが起動している状態を維持しようとしますので、ホスト障害や何らかの原因でコンテナのヘルスチェックに失敗した場合は、自動的にコンテナが入れ替えられます。
通常のOpenLDAP運用であれば可用性担保のためレプリケーションの設定が必要となりますが、この仕組みの場合、2つのOpenLDAPコンテナは同じデータを保持し、中身が書き換わることがないためそのような設定は不要となります。メリット・デメリット
この仕組みによって、得られるメリット・デメリットは下記の通りです。
サーバの管理が不要
OpenLDAPコンテナはFargate上で稼働しているため、ホストのハードウェア・OSのメンテナンスは不要です。
運用担当者が気にするべき事項はベースイメージのOSバージョン、OpenLDAPのバージョンのみとなります。OpenLDAPの基本的な機能しか使用していないので、クリティカルなセキュリティパッチ以外はほぼメンテナンス不要でしょう。
ユーザ情報化の管理が容易
一般的なOpenLDAPの管理では、ユーザの登録情報(公開鍵など)が変更される場合は、運用担当者が申請を元に変更したり、ユーザ自身に変更権限を付与して変更のための操作マニュアルを要する必要がありました。
この仕組みであれば、ユーザは使い慣れたGitのプルリクという形で登録情報の変更申請が行なえます。
また、運用担当者側のレビュー・承認もプルリクベースで行うことができ、さらにその証跡はBitBucket上に記録されます。
データの変更反映に時間がかかる
BitBucket上で管理されたユーザ情報が書き換えられた際、コンテナイメージのビルド・デプロイという流れを経て変更が反映されるため、通常のOpenLDAPサーバ運用の場合と比べて、変更反映に時間がかかります。
これについては、弊社の場合はユーザ数がそこまで多くはないことと、データの書き換え頻度が少ないため大きな問題とはなりませんでした。
緊急時のロックダウンについては、AWSのSSM RunCommandでLinuxの設定を変更することで対応する想定でした。(nsswitchの設定でローカルの
/etc/passwd
を優先するようにしてあったため、そこにロック済みの同名ユーザを追加することで緊急ロックが可能)また、同様の理由で大量のユーザ情報を格納する大規模なLDAPサーバの稼働方法としては不向きと言えます。
ユーザ情報は公開可能な情報のみに限る
BitBucketでユーザ情報を管理するため、パスワードのような、社内であっても非公開の情報を保持することができません。
基本的にはLinux認証には公開鍵認証のみを想定していたので、こちらも特に運用上困ることはありませんでした。
新しい認証方式へ
ここでは記載しませんでしたが、MySQLのユーザ認証にもこの仕組みを拡張すべく、API Gateway + Lambda + DynamoDBで別途パスワードを管理するRESTエンドポイントを作成、DynamoDB Streamでパスワード変更をトリガにLDIFをArtifactsとして出力、CodePipelineのマルチソースビルドのソースの1つとして組み込んでVaultを使って連携、みたいなことも行っていました。
しかしながら、作りかけの状態で私自身に別の大きなタスクが降ってきたこと、
パスワードの取り扱いのためリソースを拡張した結果、把握しなければいけないシステムの範囲が大きくなってしまったこと、
OpenLDAPやSSSDが古い仕組みになってきているのか、Web上でも参考となるページが少なくなっており、今後新しく参加してくれるエンジニアにとって優しくない技術要素となる懸念、
一番大きな要因として、アプリケーションのコンテナ化とログの取り扱い方法の変化というモダンなアーキテクチャへの切り替えにより、EC2へのログイン制御にユーザグループやsudo権限などの細かな管理が不要となったこと、
これら諸々の事情が重なったところに、同僚がAWS SSOとSSM Session ManagerやVaultを組み合わせた、更に面白く便利な仕組みを作ってくれたため、今回紹介した仕組みはそのままお蔵入りとすることにしました。結果として弊社では本番稼働前にお蔵入りとなってしまいましたが、OpenLDAPをDisposable/Immutableなコンテナで扱うためユーザ情報をGit上で管理する、というアプローチは我ながら面白いなと思っており、この記事が同じような問題で悩んでおられる方への一助となれば幸いです。
- 投稿日:2020-12-07T12:16:35+09:00
管理者用初期化URLを踏んでWebサービスのデータをふっとばした話
自己紹介
本職のエンジニアではありませんが、ちょっとICT系に詳しそうなやつって感じで、部署のサーバ管理を任されたりもしています。
背景
私の(当時所属していた)部署では、毎年、数週間かけて前年の各人の業務実績をとりまとめて一つの冊子(PDF)にするという仕事があり、この作業を少しでも自動化するため、Webサービスが内製されました。当初は単純に各ユーザが自分の業務実績一覧をテキストで用意してアップロードするというものでしたが、秘伝のタレのように毎年少しずつ改良されたり、大幅に作り直されて別システムから業務データを取り込んでからブラウザ上で編集できるようになったりしつつ、なんやかんやあって私が引き継ぎます。他にやりたい人もなく、ひとり鯖管です。OSはCentOS6でした。
このシステムでは、毎年新しいデータを編集するため、その作業開始時にデータを初期化する必要があります。この作業も自動化し、管理者権限でログインして管理者ページ(ここでは
https://hoge.example.com/kanri
としましょう)から起動できます。危険な作業なので、初期化しようとすれば警告が表示される仕様です。そもそもWebサービスに初期化などという機能なんてと思われるかもしれませんが、そこは内製のシステム。前年の編集データはほんとうにまったく不要なので、単純に初期化する実装になっています。さらに後述しますが、問題の本質は初期化とは無関係です。
事故
何をした(つもり)か
各ユーザに依頼していた数週間の編集作業の第1回目の期限が過ぎ、アクセスも落ち付いたころ、管理者ページに一気に行きたかった私は、ブラウザのアドレスバーに
kanri
と打ち込み、閲覧履歴から目的のURLhttps://hoge.example.com/kanri
を探してちゃちゃっと開きました。何をやらかしたか
すると、管理者ページを開いただけのはずなのに、期待に反して、初期化が完了したことを表すページが表示されました。
まさかと思いつつ、アドレスバーを確認すると
https://hoge.example.com/kanri/init
のURLがありました。閲覧履歴にあった管理者ページではなく、その隣の初期化ページを開いてしまっていました。ユーザに編集作業を依頼する前に初期化をしていたので、それが閲覧履歴にあったわけです。出てほしい警告は一切出ませんでした。やらかしたと悟りました。ユーザは200人弱、みなさん極めて多忙、そんな中で時間を割いて集中的にやってもらった作業をすべてパーにしたというわけです。大規模な商用サービスに比べれば微々たるものですが、ユーザのみなさんに同じ作業をまたやってもらわなければいけないかもというプレッシャーで胃が痛みます。
何が消えたのか
このWebサービスではDBは使用せず、データはすべて特定のディレクトリにあるユーザごとのサブディレクトリに、複数のファイルに分けて置かれていました。このデータ用ディレクトリを確認しましたが、初期化したのですから当然もぬけの空です。その当時は内部の初期化コードまで承知していませんでしたが、ようは
rm
で大量のファイルとディレクトリを削除したということです。応急処置
あわてない
あわててはいけません。まずは落ち付きます。今なら「全集中、鯖の呼吸」とつぶやくべきところです。たぶんサーバと一体化し、最善の一手となるキーに一筋の光が見えます……(知らんけど)
閑話休題。削除してしまったファイルを回復させるための最善策を考えます。
ユーザによる編集作業はほぼ一段落していて数日前のバックアップはあるにはありましたが、戻してしまうと、その間に誰が編集したかつきとめて個別に依頼していく手間と精神的負担がかかります。バックアップを戻すのは最後の手段とします。
ですが、最後の手段はある。これは気分として重要です。
データ保全
初期化がrmであったことは幸いです。truncateなどしていればどうなっていたことか。UNIX系は昔から使っているし、i-nodeを中心としたファイルシステムの概略も把握しているし、rmしてもファイルがすぐには消えないことも知っていますが、ほっておくと消えていくので時間との戦いです。このへんはどんなOSでも同じでしょう。とはいえ、リモートサーバなので下手にシングルユーザモードなどにしてネットワークアクセスができなくなると困ります。幸いこのサーバは他の用途で使っていないので、httpdを含む不要そうなサービスをすばやく止め、ディスクアクセスを最小限にします。
次に、ファイルシステムをこのままいじっていくわけにいかないので、どこかにファイルシステムのイメージを置いてゆっくり作業したいところです。このサーバにはメインのファイルシステムが一つしかないので、イメージを一時的にも同じサーバ内には置けません。sshできる方向はローカルからサーバのみ。ddはroot権限がいる。最短時間で。ということで、sshdのPermitRootLoginをyesにし、rootのパスワードはさすがに使いたくなかったので気休めですがuid=0の別アカウントを急遽用意して、このアカウントでローカルからddしました。今にして思えば、デバイスのアクセス許可を自分に出すだけでもよかったですね。
local# ssh uid0@hoge.example.com dd if=/dev/hogeroot ibs=1M >hoge.imgこれも幸いですが、このファイルシステムは16GBほどしかなく、25分ほどでイメージの転送が完了しました。やらかして、45分後です。
さらに、このファイルは原本として死守する必要があるので、別の作業用ファイルにコピーしておきます。
local# cp hoge.img hoge.wrkファイル回復
ここからは腰を据えて作業できます。
まずは、ext4のファイルシステムでrmしてしまったファイルをどう回復すればよいか、ググります。出てきた https://www.no-title.com/linux/extundelete で、extundelete というコマンドがあることを知り、インストールします。指定したファイルシステムから指定したパスのファイルを回復するようです。
local# apt install extundelete次に、ddしたファイルシステムイメージに対してどうすればファイルシステムとしてアクセスできるか、ググります。出てきた http://ng3rdstmadgke.hatenablog.com/entry/2016/10/06/064434 によれば、ファイルをループデバイスとして設定してやればマウントもできるようです。
loop14
は適当です。他のが使われていたようなので、使われていない最小の番号にしました。マウントは作業には不要ですが、ファイルシステムが認識されているかの確認用です。local# losetup /dev/loop14 hoge.wrk local# mount -o ro /dev/loop14 /mntこれら、参考にした平易な記事を書いてくださっているみなさんには感謝です。
さて、準備はできました。extundeleteは動くでしょうか。とりあえずパスのすぐわかる出力先PDFを指定して試します。
local# extundelete --restore-file /var/www/hoge/data/20xx/hoge.pdf /dev/loop14 ... Unable to restore inode 915251 (var/www/hoge/data/20xx/hoge.pdf): Space has been reallocated. ...Unable...、だめなのか。reallocated...、もう上書きされたのか。遅かったのか。
他のファイルも試します。多数ありますが、パスは機械的に生成されるので、その一覧を生成して一気に与えました。
local# extundelete --restore-files /tmp/filelist.txt /dev/loop14 ... Successfully restored file /var/www/hoge/data/20xx/.... Successfully restored file /var/www/hoge/data/20xx/.... Successfully restored file /var/www/hoge/data/20xx/.... Successfully restored file /var/www/hoge/data/20xx/.... ...すごい。Successfully!! じゃんじゃん回復して
RECOVERED_FILES
というディレクトリに作成されていきました。ごく一部に回復できなかったファイルが報告されましたが、これも幸いなことに、手動で回復できるものでした。復旧
実際には、ほかにいくつもリストからもれたファイルやリンクなどがあったのですが、それらも手作業で回復できました。あとから落ち付いてマニュアルを読むと
--restore-directory
というオプションがあり、こちらの方が断然楽ができたみたい。最後にファイルをサーバにコピーし、祈りながら各サービスを復帰させたところ、件のWebサービスがやらかし前のまま無事に動作していることが確認できました。安堵しました。
例のURLを踏んでから復旧完了まで約6時間で済み、最初の編集作業が終わった時期だったのでサーバの停止に気づいたユーザはごく少数です。ましてや、裏でこんなことがあったと知っている人はいません。
原因と対策
何が問題だったか
そもそも、初期化のページに行くには警告が出るはずでした。しかしそれが出ず、閲覧履歴から開くだけで初期化されてしまったのが問題です。
なぜそんなことが起きたか、みなさんはもう想像がついていることでしょう。
それは、初期化ページのURLをGETメソッドで叩くだけで、初期化が行われる仕様だったせいです。管理者ページからそのリンクをクリックしたときだけ、
onclick
でconfirm()
を呼んで警告を出すしくみでした。閲覧履歴からそのページを開けば、confirm()
など実行するはずもなく、GETメソッドでいきなり叩いてしまい、初期化が実行されてしまったわけです。再発しないための対策
あたりまえですが、Webサービスの内部状態を変化させる処理は、GETメソッドで起動してはいけません。Webサービスの初期化も当然内部状態を変化させます。例のリンクが、formのボタンにもなっていないただのリンクであるところで気付いて修正しておくべきでした。ボタンでもGETを使っていれば同じですが。
対策としては、POSTメソッドでアクセスしたときだけ初期化するように変更しました。初期化した結果は常に同じで羃等性があるので、DELETEを使うという手もあったかもしれません。
CSRFに関する追記(2020/12/9)
この記事に直接だけでなく、はてなブックマークやTwitterでも多数のコメントをいただき、ありがとうございます。その中で特にCSRFに関して強く言及いただきました。CSRFについては無対策であったため、本記事をそのままなぞって、GETをPOST等に修正しさえすればOKとされてしまわないよう、追記します。
GETの場合はCSRF以前の話で、自分ひとりで勝手にやらかしてしまいます。POST等にすればいわゆる自爆はなくなるのですが、URLを知っている攻撃者がPOST等のリクエストを生成するリンクやボタンを設置し、被害者がログイン状態でそれを踏むと、そのリクエストを実行してしまうというCSRF攻撃が成立してしまいます。重要な処理(商品購入や送金、メールアドレス変更、Webサービス初期化
、等)の最終確定時にCSRF対策が必要です。
本件のような内部利用システムでは、CSRF対策はRefererチェックという簡便な方法ですむことも多いと思われます。不特定多数が利用する商用システムでのCSRF対策には、きちんとセッションを管理し、最終確定前のページでセッションIDなどのトークンを埋め込んで、最終確定ページでトークンを確認してから処理を実行するのが一般的です。セッション管理にはノウハウが多数あるようで、独自実装よりもフレームワーク利用がよいかもしれません。これらの詳細は徳丸本などをご参照ください。
結論
やらかしてしまったものの、次のような幸運が重なり、最小限の影響だけで復旧できました。
- アクセスのほとんどない期間だった。
- rmによるファイルの単純な削除だった。
- サーバが他の用途に使用されていなかった。
- ファイルシステムが小さく短時間でイメージが転送できた。
- SSDではなくHDDだった。
大事なことなのでもう一度言います。Webサービスの内部状態を変化させる処理は、GETメソッドで起動してはいけません。
現在の自分はわかっていても、過去の自分も含めてみんながそう実装している保証はありません。「GET POST 使い分け」みたいなキーワードで検索して上位に出てくる解説Webページでも、このことにちゃんと触れているものはかなり少ないようです。特に、完全な「初期化」は普通のWebサービスにはなかなか存在しない処理ですし、パラメータも必要ないので、GETで実装してしまうというミスがあっても不思議ではありません。管理者用の機能の実装は手を抜きがちですが、前任者のコードも自分の過去コードでさえも信用せず確認する習慣を忘れずに。
- 投稿日:2020-12-07T09:58:19+09:00
aaPanel 無料のLinux管理パネル説明1 導入編
無料のサーバーマネジメントツール
日本語情報は全くと言って出てこないオープンソース管理パネルaaPanelの説明書となります。
aaPanelは元々Pagoda panel(宝塔)として開発され(こちらも日本では無名)、
Pagoda panelの国際版としてaaPanelがリリースされました。
githubのスター数は本家pagodaが2400スター、aaPanelが580となっています。
cpanelの代替を探している方にもおすすめです。aaPanelとは?
aaPanelはLinuxとWindowsサーバーを簡単に構築できるマネジメントツールです。
ワンクリックで各種環境をインストール可能となり、その後のモニタリングやセキュリティ設定をGUIで設定可能です。
大きな特徴として、pagodaが中国語のみLinuxとWindowsの管理が行える。
aaPanelが英語対応ですが、Linuxのみとなっています。
aaPanelでは英語化されているのでここではaaPanelの導入方法を説明していきます。
aaPanelの機能
その他簡単に構築できる機能
サーバー要件
オペレーティングシステム:CentOS / Ubuntu / Debian / Fedora / Deepin
512M以上(768M以上を推奨)
100M以上のハードディスク空き容量
クリーンサーバー(ApacheやNginxなどのサーバー環境はインストールしないでください)
aaPanel6.xバージョンはcentos7に基づいて開発されています。centos7.xを使用することをお勧めしますインストールの流れ Linux
現在、aaPanelはDebian、Ubuntu、CentOSをサポートしています。
Debianの場合
wget -O install.sh http://www.aapanel.com/script/install-ubuntu_6.0_en.sh && bash install.sh
Ubuntuの場合
wget -O install.sh http://www.aapanel.com/script/install-ubuntu_6.0_en.sh && sudo bash install.sh
CentOSの場合
yum install -y wget && wget -O install.sh http://www.aapanel.com/script/install_6.0_en.sh && bash install.sh
インストールする際にいくつかのユーザー入力が必要です。
aaPanelインストールディレクトリを要求します/www。デフォルトでは、にインストールされています。ディレクトリを変更するには、「n」と入力します。その他、管理画面にSSLの導入をするかなどを聞かれますのでご自身の希望通り進めてください。
分からない場合はすべてyesで問題ないです。インストール後のログインの流れ
インストール完了後にログインURLとIDパスワードが表示されます。
https://xxx.com:8888/ランダム8文字の英字
ポートはデフォルトで8888となりますので、セキュリティ設定で8888ポートを事前に開放してください。新しくインストールされたマシンにはランダムに8文字のセキュリティエントランス名が付けられます。
これはパネル設定でも変更できます。
このログイン情報を記録していないか覚えていない場合は、次の方法で解決できます。解決策: SSHターミナルに次のコマンドのいずれかを入力して解決します
1.パネルエントリを表示:/etc/init.d/bt default2.管理画面の入口を閉じる場合:rm -f /www/server/panel/data/admin_path.plログインパスワードを忘れた場合の対応方法(Linux)
次のコマンドを入力してパスワードをリセットします(コマンドの最後の「testpasswd」 を変更する新しいパスワードに置き換えます)
注:debianの場合/ ubuntuユーザー、root権限を持つアカウントを使用してこのコマンドを実行してください
cd / www / server / panel && python tools.py panel testpasswd
紫色のボックスは変更するパスワードです。
赤いボックスはパネルアカウントです。ログイン試行回数が上限に達してロックされている場合
以下のコマンドで解除可能です。
rm -f /www/server/panel/data/*.loginインストール完了です!
管理画面に移動して直観的にサーバーを操作してみましょう!
初回、アクセス時にワンクリックインストールで環境を一気に構築することも可能です。
バージョンや環境を指定可能で、ワンクリックインストールを進めた場合は以下のように自動で環境構築が開始されます。
管理コマンド一覧
管理機能
停止
service bt stop開始
service bt start再起動
service bt restartアンインストール
service bt stop && chkconfig --del bt && rm -f /etc/init.d/bt && rm -rf /www/server/panel現在の管理パネルのポート番号を確認する
cat /www/server/panel/data/port.plポート番号を変更する例 8881 (CentOS6 ポート番号8881に変更する例)
echo '8881' > /www/server/panel/data/port.pl && service bt restart iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport 8881 -j ACCEPT service iptables save service iptables restartポート番号を変更する,例 8881(CentOS 7 ポート番号8881に変更する例)
echo '8881' > /www/server/panel/data/port.pl && service bt restart firewall-cmd --permanent --zone=public --add-port=8881/tcp firewall-cmd --reloadMySQLマネージャ(root)のパスワードを強制的に変更,例 123456
cd /www/server/panel && python tools.py root 123456 Change control Panel login password,e.g. 123456 cd /www/server/panel && python tools.py panel 123456サイト構成の場所
/www/server/panel/vhostDelete banding domain of control panel
rm -f /www/server/panel/data/domain.confClean login restriction
rm -f /www/server/panel/data/*.loginコントロールパネルの認証IPを表示
cat /www/server/panel/data/limitip.confアクセス制限の停止
rm -f /www/server/panel/data/limitip.confドメインパーミッション確認
cat /www/server/panel/data/domain.confコントロールパネルのSSLをオフにする
rm -f /www/server/panel/data/ssl.pl && /etc/init.d/bt restartコンパネエラーログ
cat /tmp/panelBoot
データーベースエラーログ
cat /www/server/data/*.err
Site Configuration directory(nginx)
/www/server/panel/vhost/nginx
Site Configuration directory(apache)
/www/server/panel/vhost/apache
サイトデフォルトディレクトリー
/www/wwwroot
データベースバックアップディレクトリー
/www/backup/database
サイトバックアップディレクトリー
/www/backup/site
サイトログ
/www/wwwlogs
Nginx
nginx installation directory
/www/server/nginx
Nginx起動
service nginx start
Nginx停止
service nginx stop
Nginx再起動
service nginx restart
Nginxリロード
service nginx reload
nginx設定
/www/server/nginx/conf/nginx.conf
Apache
apache installation directory
/www/server/httpd
Apache起動
service httpd start
Apache停止
service httpd stop
Apache再起動
service httpd restart
Apacheリロード
service httpd reload
apache設定
/www/server/apache/conf/httpd.conf
MySQL
mysql installation directory
/www/server/mysqlphpmyadmin installation directory
/www/server/phpmyadminData storage directory
/www/server/data mysqlStart
service mysqld startStop
service mysqld stopRestart
service mysqld restartReload
service mysqld reloadmysql Configuration
/etc/my.cnfFTP
FTPインストールディレクトリ
/www/server/pure-ftpdFTP開始
service pure-ftpd startFTP停止
service pure-ftpd stopFTP再起動
service pure-ftpd restartFTP設定
/www/server/pure-ftpd/etc/pure-ftpdPHP
phpインストールディレクトリ
/www/server/phpPHP開始(PHPバージョンに置き換えてください, 例 service php-fpm-54 start)
servicephp-fpm-{52|53|54|55|56|70|71} startPHP停止(PHPバージョンに置き換えてください, 例 service php-fpm-54 stop)
service php-fpm-{52|53|54|55|56|70|71} stopRestart(PHPバージョンに置き換えてください, 例 service php-fpm-54 restart)
service php-fpm-{52|53|54|55|56|70|71} restart
Reload(PHPバージョンに置き換えてください, 例 service php-fpm-54 reload)
service php-fpm-{52|53|54|55|56|70|71} reload
PHP設定(PHPバージョンに置き換えてください, 例 /www/server/php/52/etc/php.ini)
/www/server/php/{52|53|54|55|56|70|71}/etc/php.ini
Redis
redisインストールディレクトリ
/www/server/redisRedis開始
service redis startRedis停止
service redis stop redis Configuration /www/server/redis/redis.confMemcached
memcached installation directory
/usr/local/memcachedMemcached開始
service memcached startMemcached停止
service memcached stopMemcached再起動
service memcached restartMemcachedリロード
service memcached reload
- 投稿日:2020-12-07T05:21:13+09:00
Docker をつかって RAR 形式のファイルを展開(解凍)する
Windows 10 で ubuntu Docker image と unrar をつかって RAR 形式のファイルを展開する手順です。ホスト OS の Windows 10 には RAR 展開ソフトウェアをインストールせずに、Docker コンテナで展開処理します。
RAR 形式に圧縮されたファイルを展開するためには WinRAR や 7-Zip のような RAR 圧縮ファイルを扱えるソフトウェアが当然必要になりますが、Docker を利用することによって、ホスト OS ではなくコンテナに展開プログラムをインストールし、用が済めばコンテナごと破棄する、という使い方ができます。普段から RAR 形式をよく利用するのであればソフトウェアをインストールしておけばよいですが、稀に使用する程度という人にとって、ホスト OS に専用ソフトウェアをインストールせずに済みます。
1. ubuntu イメージを取得する
ファイルの展開に使用する Linux コンテナイメージを docker hub から取得します。ここでは現時点の ubuntu:latest である 20.04 Focal Fossa を使用します。
ubuntuイメージを取得する> docker pull ubuntu Using default tag: latest latest: Pulling from library/ubuntu Digest: sha256:c95a8e48bf88e9849f3e0f723d9f49fa12c5a00cfc6e60d2bc99d87555295e4c Status: Image is up to date for ubuntu:latest docker.io/library/ubuntu:latest2. ubuntu コンテナに unrar をインストールする
初期イメージに unrar は含まれていないため、unrar をインストールしたコンテナを作成します。unrar のインストールには ubuntu のパッケージ管理ツール apt-get を利用します。
unrarをインストールする> docker run -it ubuntu /bin/bash -c "apt-get update && apt-get -y install unrar && rm -rf /var/lib/apt/lists/*" ... Reading package lists... Done Reading package lists... Done Building dependency tree Reading state information... Done The following NEW packages will be installed: unrar 0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded. ...3. コンテナから新しいイメージを作成する
ファイルを展開するときに使用する新しいイメージを作成します。イメージの名前は任意ですが、下記の例では
my/unrar
としています。まず、docker ps
でコンテナ ID を確認して(下記の例では9b720fae191a
)、docker commit
でイメージを作成し、イメージを作成した後はdocker rm
でコンテナを削除します。新しいイメージを作成する> docker ps -l CONTAINER ID IMAGE STATUS 9b720fae191a ubuntu Exited (0) 3 minutes ago > docker commit 9b720fae191a my/unrar > docker rm 9b720fae191a4. RAR 形式の圧縮ファイルを展開する
ホスト OS のファイルシステムにある RAR 形式の圧縮ファイルを展開します。下記の例では「New Text Document.rar」から同じフォルダに「New Text Document.txt」を展開しています。
docker run
は実行する度にコンテナを作成しますが--rm
オプションを指定しておくと処理終了時にコンテナが自動で削除されるようになります。RARアーカイブを展開する> docker run -v ${PWD}:/tmp -w /tmp -i --rm my/unrar unrar e -r './New Text Document.rar' UNRAR 5.61 beta 1 freeware Copyright (c) 1993-2018 Alexander Roshal Extracting from ./New Text Document.rar Extracting New Text Document.txt OK All OK使用しなくなったときは、Docker コンテナとイメージを削除します。
以上の手順のうち、新しいイメージを作成するまでの手順้は Dockerfile と
docker build
コマンドで代用することもできます。Dockerfile を下記のような内容で用意しておいてdocker build -t my/unrar .
を実行すると、my/unrar イメージからすぐに unrar を実行できる(上記 4 の手順)状態になります。この流れは unrar に限らず、Windows で Linux のプログラムを実行したい、という場面に応用できます。DockerfileFROM ubuntu:latest # set a directory for the app WORKDIR /tmp # install unrar RUN apt-get update && apt-get -y install unrar && rm -rf /var/lib/apt/lists/*
- 投稿日:2020-12-07T03:53:22+09:00
nlコマンドでの空行の取り扱い
いままで特に触れてきませんでしたが、
nl
はデフォルトで空行(改行だけの行)に行番号を出力しません。これは行番号を出力する機能を持つ他のコマンドとは大きく異なる点だと思います。空行を含むデータの行番号
まずは空行に対して
nl
がどんな動作をするのか確かめてみましょう。echo
は-e
を指定することで\n
を改行コード(LF
)として出力します。$ echo -e 'a\n\nb' a b $ echo -e 'a\n\nb' | nl 1 a 2 b確かに空行に行番号は出力されません。
空行と判定される条件
スペースや
CR
改行(\r
)を含む行など、見た目は空行に見えるデータも試してみましょう。$ echo -e 'a\n \nb' | nl 1 a 2 3 b $ echo -e 'a\r\n\r\nb\r' | nl 1 a 2 3 b一見空行に見えても行番号が振られています。
LF
以外の文字が含まれる行は「空行」とはみなされないようです。UNIX系のコマンドなので、LF
のみを改行として取り扱うのは当然の結果です。Windowsなど改行がCRLF
で保存されたデータを扱う場合は気をつける必要がありそうです。空行に付加されるデータ
セパレータ
では、-sオプションの記事で説明したセパレータは出力されているのでしょうか。実はcoreutilsの
nl
とBSD系のnl
では結果が異なります。タブのままでは見えないので-s
でわかりやすく@@@
に変更して検証してみましょう。coreutils$ echo -e 'a\n\nb' | nl -s @@@ 1@@@a 2@@@bbusybox$ echo -e 'a\n\nb' | busybox nl -s @@@ 1@@@a 2@@@bBSD(macOS)$ echo -e 'a\n\nb' | nl -s @@@ 1@@@a @@@ 2@@@bBSD系の
nl
だけが空行でもセパレータを出力しています。BSD系の
nl
のセパレータとPOSIXこのように実装によって異なる挙動を発見した場合は、標準であるPOSIXを確認してみましょう。
<empty>
When line numbers are suppressed for a portion of the page; the <separator> is also suppressed.これは、-nオプションの記事でも引用した「OUTPUT」の一部分の記載になります。
POSIXによると「行番号が抑制されるとき、セパレータもまた抑制される」とあります。つまりBSD系のnl
のこの挙動は「POSIXに準拠していない仕様」あるいは「ソフトウェアのバグ」ということになります。STANDARDS
The nl utility conforms to IEEE Std 1003.1-2001 ("POSIX.1").さらに、Manpageを参照すると「標準」としてPOSIXが引用されています。おそらくはバグということになるのでしょう。
ちなみに、coreutilsのManpageを参照すると、
-s
について以下のように書かれています。coreutils$ man nl | grep -A1 'number-separator' -s, --number-separator=STRING add STRING after (possible) line numberこの
(possible)
という部分が、「行番号をつけるところだけ」という補足のようです。coreutilsの
nl
での空行の取り扱いデフォルトのタブのときも検証してみましょう。
xxd
というvim
に含まれるコマンドユーティリティでバイナリを16進数のテキストで出力します。coreutils$ echo -e 'a\n\nb' | nl | xxd 00000000: 2020 2020 2031 0961 0a20 2020 2020 2020 1.a. 00000010: 0a20 2020 2020 3209 620a . 2.b.BSD(macOS)$ echo -e 'a\n\nb' | nl | xxd 00000000: 2020 2020 2031 0961 0a20 2020 2020 2009 1.a. . 00000010: 0a20 2020 2020 3209 620a . 2.b.16進数表示されている真ん中のブロックの1行目右端7バイトに注目してください。coreutilsは
20 2020 2020 2020
でBSD系は20 2020 2020 2009
ですが、この部分がちょうど元データの2行目の文字列(改行0x0a
は含まず)にあたります。つまり、coreutilsのnl
でも空行を一切変更しないわけではなく、行番号とセパレータを表示していないだけです。右揃えにするためのスペース0x20
が出力されており、さらにセパレータのタブ0x09
の分まで1文字余計に付加されています。あまり大きな問題は無いかもしれませんが、これは
nl
を2つ重ねて使う場合には想定した挙動と異なる結果になるかもしれません。coreutils$ echo -e 'a\n\nb' | nl | nl 1 1 a 2 3 2 b空行に付加されるデータを取り除く
coreutilsの空行に付加されるデータを消せるのか、他のオプションとの組み合わせを試してみましたが難しいようです。
coreutils$ echo -e 'a\n\nb' | nl -n ln -w 1 -s '' | xxd 00000000: 3161 0a20 0a32 620a 1a. .2b.coreutilsでは
-w
は1
以上の値しか受け付けませんので0
を指定することはできません。一方、busyboxもほとんど同じ挙動ですが、-w
に0
が指定できるので空行のまま取り扱うことはできるようです。busybox$ echo -e 'a\n\nb' | busybox nl -w 0 -s '' | xxd 00000000: 3161 0a0a 3262 0a 1a..2b.しかし、行番号についてもセパレータが消えてしまいますので実用するのは難しいでしょう。現実的に空行を元に戻したい場合は、
sed
などを利用するしかなさそうです。coreutils$ echo -e 'a\n\nb' | nl | sed 's/^[ ]*$//' | nl 1 1 a 2 2 b
ToDo
BSD系の
nl
のPOSIX準拠についてManpageには最新のPOSIX.1-2017ではなくPOSIX.1-2001準拠となっていますので、その変更差分を調べる必要があります。後日確認したら更新する予定です。
- 投稿日:2020-12-07T03:00:23+09:00
TypeScriptのアップデート中に EEXIST のエラーが表示されてちょっと詰まったことの解決手順
今回は今までなぜかグローバルのTSのアプデができずに無視してたところついに立ち向かった(面倒くさがり)
そのせいでバージョン 1.5.3 に甘んじていました。npm i -g typescript@latestで最新版のTypeScriptにアプデしようとしたら案の定エラーが表示。
npm ERR! code EEXIST npm ERR! syscall symlink npm ERR! path ../lib/node_modules/typescript/bin/tsc npm ERR! dest /Users/myuser/.nodenv/versions/12.16.0/bin/tsc npm ERR! errno -17 npm ERR! EEXIST: file already exists, symlink '../lib/node_modules/typescript/bin/tsc' -> '/Users/myuser/.nodenv/versions/12.16.0/bin/tsc' npm ERR! File exists: /Users/myuser/.nodenv/versions/12.16.0/bin/tsc npm ERR! Remove the existing file and try again, or run npm npm ERR! with --force to overwrite files recklessly. npm ERR! A complete log of this run can be found in: npm ERR! /Users/myuser/.npm/_logs/2020-12-06T17_00_41_920Z-debug.lognodenvを使っている人が遭遇したことあるかもしれないエラー。npm installなどでも遭遇する人がいるらしいが詳しくは見ていない。
再インストールであっさり解決?
結果としては
npm ERR! Remove the existing file and try again, or run npmこれの言う通りにして解決した。このエラーで言うところの existing file は
npm ERR! dest /Users/myuser/.nodenv/versions/12.16.0/bin/tscのことだから、直接 tsc に対して " rm -rf tsc " で削除した。
これでOK。なはず。typescriptアップデートの再チャレンジ
しかしここで再びアプデコマンドを打ったところなんとまた同じエラーが発生。
今度は、「tscフォルダ」ではなく「tsserverフォルダ」に対して怒られた。そのため tsc と同じように削除した。3度目の正直でついに
その後、再び
npm i -g typescript@latestで無事に最新版にアプデできた。バージョンは 4.1.2。
1.5.3から4.1.2はなかなかの跳躍。npm ERR! syscall symlink ってなんだ
タイトルにもある通り、つまづいた理由はこのエラーがよくわからなくて放置。ちゃんと調べてなかったのでよくわからなかった笑
調べたところ symlink とはショートカットのディレクトリ名を意味しており、プログラミングとは関係なく日常でもショートカットのファイルなどを作成する機会があると思うがそれと同じものになるとの理解であってるかと。つまりsymlinkによってAというショートカットのディレクトリ(中身は入っていない)を呼び出すことで、本体であるBを呼び出すことができるらしい。
今回のケースで言えば具体的には
Aがこれ(npm ERR! path ../lib/node_modules/typescript/bin/tsc)
Bがこれ(npm ERR! dest /Users/myuser/.nodenv/versions/12.16.0/bin/tsc)
に当たると思われる。というか path は文字通りの意味で、 dest が目的地であり本体のことを指しているはず。そのため今回は本体のフォルダを削除することで再インストールできたということになります。
nodenvの場合は各nodeバージョン毎に入っているライブラリバージョンも異なるためショートカットという形で呼び出しているのかなと思います。問題は解決できたけれど...
しかし結局のところなぜエラーが生じたのかわからかった。。
他のライブラリやモジュールでも同じエラー生じるはずなので。npm i -g typescript@latestバージョンが古すぎてそのまま上書きアプデできなかったとか??
- 投稿日:2020-12-07T01:11:48+09:00
Gecko Linux Install
GeckoLinux ←クリック(新窓) をインストールしました。
本家のサイトからDLし Install は簡単です。
DistroWatch の解説では
「Linux spin based on the openSUSE distribution.」
日本語は ibus がデフォとなっていますが
Fcitx + Mozc を使いたい・・
Language 等を Install した後、何故か勝手に更新が始まります。
終わると、 Yast ソフトウェアーセンター から Fcitx Mozc 等をInstall
この時、面倒なので ibus を削除しました。
このままでは日本語になりませんでした。
お馴染みとなっている3行のText を追加します。
「export GTK_IM_MODULE=fcitx
export QT_IM_MODULE=fcitx
export XMODIFIERS=@im=fcitx」
これを home .bashrc に追加
メソッドのトリガーを「zenkakuhankaku」にして
日本語入力、完了しました。
OpenSUSE 何となく個人的には重たいという印象があったんですが
Core 2 Duo の10年前のノートPCでサクサクと動いてくれます。