まだプログラマーですが何か?

プログラマーネタ中心。たまに作成したウェブサービス関連の話も https://twitter.com/dotnsf

タグ:desktop

タイトルどおりの内容のエラーが発生したので、その原因と解決策を探った記録をブログにまとめました。

環境としては以下の図のようなものです。1台の Windows 10 PC の中に Docker Desktop を導入・起動し、MySQL サーバーのイメージからコンテナを作って 3306 番ポートで公開起動しました。この環境に WSL(2) の MySQL CLI を使って、localhost:3306 の MySQL サーバーにログインする、というだけの内容なのですが、ログイン時にコネクションエラーが発生してしまう、という症状が出ていました:
20210612


具体的に紹介します。今回使った MySQL のコンテナイメージはこちらです。厳密には mariadb を使っています。同様の現象が発生すると思うので、他の MySQL 系イメージでも構いません:
https://hub.docker.com/r/linuxserver/mariadb


Docker Desktop を使ってこのイメージからコンテナを作成します。WSL を起動するなどして docker コマンドが使える状態で以下のコマンドを実行します(目的は Docker Desktop 内のコンテナとして起動することなので、このコマンド自体は WSL から実行しなくても構いません):
$ docker run -d --name=mariadb -e PUID=1000 -e PGID=1000 -e MYSQL_ROOT_PASSWORD=root -e TZ=Asia/Tokyo -e MYSQL_DATABASE=mydb -e MYSQL_USER=user -e MYSQL_PASSWORD=P@ssw0rd -p 3306:3306 --restart unless-stopped linuxserver/mariadb

こんな感じで、Docker Desktop 内のコンテナとして MySQL が起動します:
2021061301


指定したオプションはコンテナイメージのドキュメントを参考に指定しています。上の例では root のパスワードは root 、利用ユーザーは user 、利用ユーザーのパスワードは P@ssw0rd 、利用データベース名を mydb、コンテナ名は mariadb、などを指定しています(適当に変更いただいても構いません)。ポート番号に -p 3306:3306 を指定しているので、ローカルホストの 3306 番ポートからも(公開されているので)アクセスできるはずです。事前準備はここまで。

ではこの方法で Docker Desktop 内に起動した MySQL(mariadb) に、WSL から MySQL CLI で接続してみます。上述のオプションであれば以下のコマンドで接続できるはずです:
$ mysql -u user -pP@ssw0rd -h localhost mydb

しかし実際には以下のようなエラーが表示されてしまいます:
$ mysql -u user -pP@ssw0rd -h localhost mydb
ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2 "No such file or directory")

ユーザー名やパスワード、データベース名は間違っておらず、接続先も localhost だから間違えようがないはずです。ポート番号もデフォルトの 3306 のままなので特別なオプションも不要のはず・・・ ではなぜエラーになってしまうのでしょうか?


改めてエラーメッセージをよく見ると "Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock'" と表示されています。ちなみにこのファイルは存在していません(/var/run/mysqld というディレクトリが存在していません):
$ ls -la /var/run/sqld/mysqld.sock
ls: cannot access '/var/run/sqld/mysqld.sock': No such file or directory

このエラーメッセージでわかる人もいると思うのですが、MySQL コマンドは localhost が対象の場合はデフォルトで「ソケット接続」という方法で接続を試みます。そしてこのソケット接続をする場合の情報を /var/run/sqld/mysqld.sock というファイルで管理しているため、このファイルを読み込もうとしているのでした。

しかし、今回の環境では WSL 内には MySQL サーバーは起動していません。WSL 内からの docker コマンドで起動してはいますが、実体は Windows にインストールされた Docker Desktop のコンテナとして起動しています。要は「WSL と同じマシン上で動いてはいて、ポートも公開されているけど、WSL から直接ソケット接続できる状態で動いていない」のです。これがエラーの原因で、エラーメッセージの理由でもあります。

では、エラーなしに WSL から MySQL に接続するにはどのようなコマンドにすればいいでしょうか? 答はシンプルで「ソケット接続ではなく、TCP 接続するようなオプションを指定」することで解決できます。具体的には以下のように --protocol=TCP オプションを付けて実行します:
$ mysql -u user -pP@ssw0rd --protocol=TCP -h localhost mydb
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 11
Server version: 10.4.18-MariaDB-1:10.4.18+maria~bionic-log mariadb.org binary distribution

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MariaDB [mydb]>

今度は無事に接続できました。「localhost の罠」にかかった時の話でした。


普段、あまり Windows サーバーを使うことがない中でクラウド上の Windows サーバーにリモートデスクトップ接続をして作業する、という機会がありました。そこで遭遇したトラブルと、その解決方法の自分向け備忘録です。


まずは発生したトラブルの状況を説明します。某クラウド上に Windows サーバーインスタンスを作成・用意しました。ログイン時のクレデンシャル(ユーザー名&パスワード)も分かっていて、サーバー・ネットワークへの VPN も接続したのでプライベート IP アドレス宛で接続することができるはず、という状況です:
2020091501


いざリモートデスクトップ接続を試みます。コンピューター欄に IP アドレス、そしてユーザー名にはログイン用のクレデンシャルで確認したユーザー名(図では Administrator)を指定して「接続」します:
2020091502


するとログインパスワードを聞かれます、ここまでは想定通り。同様にしてクレデンシャルで確認ずみのログインパスワードを入力して「OK」をクリック。これでリモートデスクトップ接続できるはず・・・:
2020091503


・・・だったのですが、エラーが発生してログインに失敗してしまいました。入力ミスはしていないし、ネットワーク的に繋がっていない相手だとしたらパスワードを聞かれることもないし、、、原因はなんだろう?? と、よく見るとユーザー名が入力した "Administrator" ではなく "Administrator@xxx.xxx" となっていました。なお "@xxx.xxx" 部分は会社のドメイン名です。何度か同じ手順を実行したのですが、常にこのドメイン名部分が自動的に(というか勝手に)付加されてしまい、正しいログインユーザー名ではなくなっていました。ログインエラーの原因はおそらくこれでしょう:
2020091504


作業に使った Windows PC は会社貸与のもので、詳しくはわかりませんが会社の運用ポリシーに従って集中管理されているものです。おそらくですがその関係でリモートデスクトップ接続時のログインユーザー名に "@xxx.xxx" というドメイン名までが(自動的に)付与されてしまっているのだと思います。この辺りあまり詳しくないのですが、そう考えるとこの挙動自体は納得できるものではあります。

ただログインユーザー名が勝手に変更されてしまっては、いつまでたってもクラウドの Windows サーバーにログインすることができません。会社側の運用ポリシーに原因があるのだとすれば、その運用ポリシーを変更することでも解決できるかもしれませんが、残念ながら(多くのケースがそうであると想像しますが)自分は運用ポリシーを変更できるような立場ではありません。直接の原因の究明も去る事ながら、この状況を Windows ユーザー側の操作だけで解決する方法はないか? というのが今回のブログテーマでした。


で、その応急処置的な解決方法がわかりました。先程のエラー画面内の「その他」と書かれた箇所をクリックします:
2020091505


するとログインユーザーを選択する箇所が表示されるので、まずはここで「別のアカウントを使用する」を選択します:
2020091506


改めてログインユーザー名とパスワードを入力する画面に遷移します。ここでログインユーザー名の頭に .\ を付けたものを指定します(パスワードは本来のものをそのまま指定します)。そして「OK」を押します:
2020091507


環境によってはセキュリティ証明書に関する警告ダイアログが出ることがあるかもしれませんが、その場合は「はい」を選択します:
2020091508


すると無事にリモート先の Windows デスクトップが表示されました!:
2020091509


運用ポリシーによって会社ドメインが強制されてしまうようなケースでも、ログイン名の頭に .\ を付けることでログインユーザー名のドメインを強制指定して上書きすることでなんとかエラーが回避できるようでした。


IBM LinuxONE(メインフレーム版 Linux)の挑戦シリーズです。今回は RHEL6.x のインスタンス上に X Window のデスクトップ環境を導入してみます。加えてこのデスクトップ環境にリモートアクセスできるよう VNC サーバーも合わせて導入します:
2017012201


まず前提条件として LinuxONE の環境が必要になりますが、今回は「無料で最大 120 日間クラウド上の LinuxONE インスタンスが使える」という IBM LinuxONE コミュニティクラウドの環境を使って RHEL 6.x のサーバーを作り、その上に今回の環境構築を行うことにします。そこまでの環境構築手順についてはこちらを参照ください:
IBM LinuxONE コミュニティクラウドを使う(2017年1月版)


さて、LinuxONE と言っても RHEL(RedHat Enterprise Linux) であることには変わりありません。ということは普通は以下のコマンドで X Window のデスクトップ環境が導入できることをご存知の人も少なくないと思います:
# yum groupinstall "Desktop"

ということは LinuxONE でも同じコマンドを実行するだけでよいのでは・・・と思うかもしれませんが、残念ながら LinuxONE の RHEL6.x では yum は動きますが、グループ情報が登録されておらず、"groupinstall" コマンドが使えない模様でした(赤字および青字が yum groupinstall コマンド実行後の出力結果です):
# yum groupinstall "Desktop"
Loaded plugins: product-id, refresh-packagekit, search-disabled-repos, security,
              : subscription-manager
This system is not registered to Red Hat Subscription Management. You can use subscription-manager to register.
Setting up Group Process
RHEL67                                                   | 3.0 kB     00:00
rhel67optional                                           | 2.9 kB     00:00
rhel67supp                                               | 2.9 kB     00:00
Warning: Group Desktop does not exist.
Error: No packages in any requested group available to install or update

ではどうするか? 要は「groupinstall がコマンドが使えないなら、install コマンドを使えばいいじゃない」というわけで、yum groupinstall コマンドで実行されるのと同じコマンドを yum install コマンドで実行してしまいましょう。この件について詳しくはこちらのブログエントリで紹介しているので、興味がある方はこちらも参照ください:
yum の groupinstall でインストールされるパッケージを確認する


具体的には以下のコマンドを実行して、"Desktop" グループに含まれるはずの個別パッケージをまとめてインストールするよう指定します:
# yum install NetworkManager NetworkManager-gnome alsa-plugins-pulseaudio at-spi control-center dbus gdm gdm-user-switch-applet gnome-panel gnome-power-manager gnome-screensaver gnome-session gnome-terminal gvfs-archive gvfs-fuse gvfs-smb metacity nautilus notification-daemon polkit-gnome xdg-user-dirs-gtk yelp control-center-extra eog gdm-plugin-fingerprint gnome-applets gnome-media gnome-packagekit gnome-vfs2-smb gok openssh-askpass orca pulseaudio-module-gconf pulseaudio-module-x11 vino

ついでというわけではないのですが、X Window のデスクトップを導入しても、ネットワーク越しにデスクトップが利用できないと意味がありません。というわけで RHEL6.x で使える VNC サーバーとして TigerVNC を導入することにします:
# yum install tigervnc-server

なお、TigerVNC の導入そのもの(インストール後の設定方法含む)について、こちらで詳しく紹介しているので一度参照ください:
CentOS に VNC サーバーを導入する


TigerVNC サーバー導入&設定後に再起動し、VNC ビューワで IP アドレスとポート番号を指定してアクセスすると、LinuxONE に導入された X Window のデスクトップ環境にアクセスできます:
2017012202


これで LinuxONE をデスクトップとして使ったり、GUI 必須のアプリケーションが利用できるようになりますね。
 

ラズベリーパイベースのラップトップ PC である PiTop を、デスクトップ環境として整備しています。さすがにメイン機として使うのは・・・ ですが、サブ機として支障なく使える程度にできないだろうか、と思っています。

ただ改めてラズパイを使ってみると、色々足りない部分も見えてきます。それら足りない部分を導入する手順を調べてみました。ちなみに PiTop で使う OS は Raspbian Jessie とします。


日本語表示

導入手順によってはインストール時にある程度設定できるので、初めから日本語表示ができる環境を手にしている人もいるかもしれませんが念のため。 以下の手順で日本語が正しく表示できるように(□みたいな文字にならないように)して、更に日本語フォントを導入します:
$ sudo raspi-config

"Innternnationalisation Options" 選択
"Change Locale" 選択
"ja_JP.UTF-8" 選択し、デフォルト言語に設定し raspi-config を終了
$ sudo apt-get install ttf-kochi-gothic xfonts-intl-japanese xfonts-intl-japanese-big
2016072501



日本語入力

日本語が正しく表示できても、入力となると別の設定が必要です。今回は IBUS を使って日本語を入力できるよう、必要なアプリを導入して日本語入力設定を行います:
$ sudo apt-get install ibus-anthy

メニューから「設定」-「IBUS の設定」を選択
「インプットメソッド」タブで「日本語 - Anthy」を設定

2016072502

これで画面右上の IBUS アイコンをクリックすることで入力言語を切り替えることができるようになります。


Eclipse

自分がこれがないと Java アプリが作れません。というほど依存している統合開発環境である Eclipse のラズパイ版を導入します。ラズパイ用の Pleiades (ちなみに Eclipse 3.8 ベース)が用意されていたとは・・・
$ sudo apt-get install pleiades

20160728



スクリーンショット

ラズパイでスクリーンショットを撮るにはいくつかの方法があります。自分はこれまでは直接スクリーンショット撮ることはなく、VNC 経由で別PCから画面ショットを撮っていました。が、今回は折角デスクトップ環境を手に入れることができたので、単体で取得できる scrot を使うことにします:
$ sudo apt-get install scrot


その他

個人的によく使う screenvim を入れておきます:
$ sudo apt-get install screen vim

screen と同じくらい使う tmux も Raspbian 上で使うことができそうです:
$ sudo apt-get install libevent-dev libncurses5-dev
$ cd /tmp
$ wget https://github.com/tmux/tmux/archive/2.2.tar.gz
$ tar xvfz 2.2.tar.gz
$ cd tmux-2.2
$ ./configure && make
$ sudo make install

とあるメインフレームコンテストに参加するために IBM 3270 環境が必要になるのでコマンドライン版を導入します:
$ cd /tmp
$ mkdir 3270
$ cd 3270
$ wget http://downloads.sourceforge.net/project/x3270/x3270/3.3.14ga11/suite3270-3.3.14ga11-src.tgz
$ tar xavf suite3270-3.3.14ga11-src.tgz
$ cd c3270-3.3
$ ./configure && make
$ sudo make install

自分はいい歳したオッサンなので、オッサンが喜ぶような X11 アプリをまとめて導入しておきます:
$ sudo apt-get install x11-apps

これで懐かしい "xeyes" などが使えるようになります:
2016073105



その他プログラミング言語やミドルウェアについては適当に。

Java のコードからブラウザを起動できることを知りました。
環境依存とかで面倒そう、、と思っていたのですが、AWT の Desktop クラスを使うことで比較的簡単に実現できちゃいました:
import java.awt.Desktop;
import java.net.URI;

  :
  :

String uriString = "http://manholemap.juge.me/"; // 開くURL
Desktop desktop = Desktop.getDesktop();
try{
  URI uri = new URI( uriString );
  desktop.browse( uri );
}catch( Exception e ){
  e.printStackTrace();
}

  :
  :

これだけで指定した URL のページ(この例だとマンホールマップ)がデフォルトブラウザで開きます。

これがどんな時に便利かというと、一般的な Web アプリケーションの中で(サーブレットや JSP で)Java を使う時は HttpServletRequest/HttpServletResponse クラスなどから UI 部分との連携ができるのですが、スタンドアロン Java プログラムや、IBM Notes などのスタンドアロンアプリケーションから Java を使おうとすると、コードは実行できても UI 部分との連携がしにくくて、「実行結果をどうやって見せるか」の問題があるのでした。Java コンソールに出力するくらいはできても、それを見てもらうのも至難の技だし、そもそも見栄えも悪い。

その点、ブラウザを起動できてしまえば、パラメータに実行結果を含めちゃったりすることで実行結果を渡す方法もあるし、見栄えも HTML/CSS で自由度高く作れるしで、重宝します。

なお、java.awt.Desktop クラスはこれ以外でもファイルを関連付けられたアプリで開く open メソッドや、印刷する print メソッドなど、デスクトップ関連の便利なメソッドが用意されています。ノーツ系の皆さんは覚えておくと便利かも(とっくに知ってたらごめんなさい):
Desktop(Java Platform 7)






 

このページのトップヘ