20210411のMySQLに関する記事は8件です。

SELECT文でデータベースの特定のスキーマの各テーブルのサイズを確認する

SELECT文でデータベースの特定のスキーマの各テーブルのサイズを確認する データベースの見積もりなどの時に既存のDBがどれくらいのサイズかを確認するために時々使うのでメモ DB_name_hereのところをデータサイズをSELECTしたいdb名を入れる SELECT table_name , engine , table_rows AS tbl_rows , avg_row_length AS rlen , floor((data_length + index_length) / 1024) AS allkb , floor((data_length) / 1024) AS dkb , floor((index_length) / 1024) AS ikb FROM information_schema.tables WHERE table_schema='DB_name_here' ORDER BY (data_length + index_length) DESC; table_name(テーブルの名称) engine(DBエンジンの種類) ・・・ InnoDB、MyISAM、MEMORYなど tbl_rows(レコード件数) rlen(平均レコードサイズ[単位: Byte]) allkb(テーブル全体のサイズ[単位: KB]) dkb(テーブル内のデータが占めるサイズ[単位: KB]) ikb(テーブル内のインデックスが占めるサイズ[単位: KB]) 参考: https://www.wakuwakubank.com/posts/323-mysql-capacity/ http://www.rexent.co.jp/blog/mysql-%E5%90%84%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E6%AF%8E%E3%81%AB%E5%AE%B9%E9%87%8F%E3%82%92%E7%A2%BA%E8%AA%8D%E3%81%99%E3%82%8B
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

二进制安装MySQL 8.0

1. 二进制安装MySQL 8.0 参考MySQL 8.0官方手册:https://dev.mysql.com/doc/refman/8.0/en/binary-installation.html 1.1 卸载之前安装或镜像自带的MySQL或Mariadb for i in $(rpm -qa|egrep 'mysql|mariadb');do rpm -e --nodeps $i;done rm -rf /var/lib/mysql && rm -rf /etc/my.cnf && rm -rf /usr/share/mysql && rm -rf /etc/my.cnf.d 1.2 安装依赖包 很多镜像都自带了这些依赖 yum -y install libaio numactl-libs 1.3 下载二进制包并解压 MySQL社(mian)区(fei)版下载地址:https://dev.mysql.com/downloads/mysql/ wget -P /apps https://dev.mysql.com/get/Downloads/MySQL-8.0/mysql-8.0.23-linux-glibc2.12-x86_64.tar.xz cd /apps tar xf mysql-8.0.23-linux-glibc2.12-x86_64.tar.xz 嫌解压后的文件夹名称太长的话可创建软连接 ln -s /apps/mysql-8.0.23-linux-glibc2.12-x86_64 /apps/mysql 1.4 创建组和用户 groupadd mysql;useradd -r -g mysql -s /bin/false mysql 递归修改MySQL文件夹的属主和属组 chown -R mysql.mysql /apps/mysql 1.5 配置环境变量 echo 'PATH=/apps/mysql/bin:$PATH' > /etc/profile.d/mysql.sh source /etc/profile.d/mysql.sh 1.6 创建数据库目录并新建配置文件 配置文件根据自己需求和主机性能来写 mkdir -p /data/mysql/{data,log,binlog,conf,tmp} cat > /data/mysql/conf/my.cnf <<EOF [mysqld] lower_case_table_names = 1 user = mysql server_id = 1 port = 3306 default-time-zone = '+08:00' enforce_gtid_consistency = ON gtid_mode = ON binlog_checksum = none default_authentication_plugin = mysql_native_password datadir = /data/mysql/data pid-file = /data/mysql/tmp/mysqld.pid socket = /data/mysql/tmp/mysqld.sock tmpdir = /data/mysql/tmp/ skip-name-resolve = ON open_files_limit = 65535 table_open_cache = 2000 #################innodb######################## innodb_data_home_dir = /data/mysql/data innodb_data_file_path = ibdata1:512M;ibdata2:512M:autoextend innodb_buffer_pool_size = 12000M innodb_flush_log_at_trx_commit = 1 innodb_io_capacity = 600 innodb_lock_wait_timeout = 120 innodb_log_buffer_size = 8M innodb_log_file_size = 200M innodb_log_files_in_group = 3 innodb_max_dirty_pages_pct = 85 innodb_read_io_threads = 8 innodb_write_io_threads = 8 innodb_thread_concurrency = 32 innodb_file_per_table innodb_rollback_on_timeout innodb_undo_directory = /data/mysql/data innodb_log_group_home_dir = /data/mysql/data ###################session########################### join_buffer_size = 8M key_buffer_size = 256M bulk_insert_buffer_size = 8M max_heap_table_size = 96M tmp_table_size = 96M read_buffer_size = 8M sort_buffer_size = 2M max_allowed_packet = 64M read_rnd_buffer_size = 32M ############log set################### log-error = /data/mysql/log/mysqld.err log-bin = /data/mysql/binlog/binlog log_bin_index = /data/mysql/binlog/binlog.index max_binlog_size = 500M slow_query_log_file = /data/mysql/log/slow.log slow_query_log = 1 long_query_time = 10 log_queries_not_using_indexes = ON log_throttle_queries_not_using_indexes = 10 log_slow_admin_statements = ON log_output = FILE,TABLE master_info_file = /data/mysql/binlog/master.info EOF 1.7 安装后的设置和测试 参考MySQL 8.0官方手册:https://dev.mysql.com/doc/refman/8.0/en/postinstallation.html 排错请查看错误日志: tail -f /data/mysql/log/mysqld.err 1.7.1 初始化数据目录 使用--initialize-insecure,不会root生成密码。 mysqld --defaults-file=/data/mysql/conf/my.cnf --initialize-insecure --user=mysql 1.7.2 启动mysqld mysqld_safe --defaults-file=/data/mysql/conf/my.cnf pgrep mysql 1.7.3 登录MySQL并设置密码 首次登录无需密码(如报错请检查以前的配置文件是否删除干净) mysql -S /data/mysql/tmp/mysqld.sock 设置密码 ALTER USER 'root'@'localhost' IDENTIFIED BY 'password'; 刷新权限列表 flush privileges; 查看登录主机,用户,密码信息 select host,user,authentication_string from mysql.user; 1.7.4 将登录的sock软链接到tmp目录 ln -s /data/mysql/tmp/mysqld.sock /tmp/mysql.sock 1.8 使用systemd管理MySQL服务 参考MySQL官方手册: https://dev.mysql.com/doc/mysql-secure-deployment-guide/8.0/en/secure-deployment-post-install.html https://dev.mysql.com/doc/refman/8.0/en/using-systemd.html service配置文件 cat > /usr/lib/systemd/system/mysqld.service <<EOF [Unit] Description=MySQL Server Documentation=man:mysqld(8) Documentation=http://dev.mysql.com/doc/refman/en/using-systemd.html After=network.target After=syslog.target [Install] WantedBy=multi-user.target [Service] User=mysql Group=mysql Type=notify TimeoutSec=0 ExecStart=/apps/mysql-8.0.23-linux-glibc2.12-x86_64/bin/mysqld --defaults-file=/data/mysql/conf/my.cnf $MYSQLD_OPTS EnvironmentFile=-/etc/sysconfig/mysql LimitNOFILE = 10000 Restart=on-failure RestartPreventExitStatus=1 Environment=MYSQLD_PARENT_PID=1 PrivateTmp=false EOF 如启动过mysql需要先将所有mysql进程kill掉,否则会占用sock套接字导致无法使用systemctl启动 pgrep mysql kill [MYSQLPID] 重新加载systemctl服务,并启动mysqld systemctl daemon-reload systemctl start mysqld
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[MySQL] DBサーバのディスク容量が少なくなった時に確認する項目

はじめに 担当しているシステムのMySQLサーバのディスク容量がそろそろ一杯になりそう。 良い機会なので、DBサーバでディスク容量の問題に直面した場合にチェックすべきことなどをまとめた。 ※ 日本語の方が読みやすいのでMySQLのリファレンスへのリンクは5.6の日本語版。 DBサーバでディスク容量の問題に直面した場合にチェックすべきこと サービスで使っているデータベースのデータサイズを確認する。 バイナリログのサイズを確認する。 サービスで使っているデータベースのデータサイズを確認する。 データベースのディスク使用状況確認用SQL データベースのディスク使用状況 SELECT FORMAT(SUM(data_length + index_length + data_free), 0) FROM information_schema.tables WHERE table_schema=database(); テーブル毎のディスク使用状況確認用SQL テーブル毎のディスク使用状況 SELECT table_name , engine , FORMAT(table_rows, 0) AS table_rows , FORMAT(avg_row_length, 0) AS avg_row_length , FORMAT(data_length, 0) AS data_Byte , FORMAT(index_length, 0) AS index_Byte , FORMAT(data_free, 0) AS data_free_Byte , FORMAT((data_length + index_length + data_free), 0) AS all_Byte FROM information_schema.tables WHERE table_schema=database() ORDER BY (data_length + index_length + data_free) DESC; 各カラムが何を示しているかはMySQLのリファレンスを参照してください。 MySQLリファレンス 13.7.5.37 SHOW TABLE STATUS 構文 フラグメンテーションを解消するSQL フラグメンテーションを解消するSQL OPTIMIZE TABLE table_name; OPTIMIZE [NO_WRITE_TO_BINLOG | LOCAL] TABLE table_name; 本番環境でいきなりこのSQLを実行するのは避けた方がよさそう。 STG環境でリハーサルして どれくらい時間がかかるのか DBサーバメモリは大丈夫か バイナリログの容量はどれくらい増えるのか などを確認し、影響度合いを把握しておく方がいいと思う。 あと、OPTIMIZE TABLEをオプションを付けて実行すると、バイナリログに内容を書き込まないらしい。 リファレンスによると、 デフォルトでは、サーバーは OPTIMIZE TABLE ステートメントをバイナリログに書き込み、それらがレプリケーションスレーブにレプリケートされるようにします。ロギングを抑制するには、オプションの NO_WRITE_TO_BINLOG キーワード、またはそのエイリアス LOCAL を指定します。 MySQLリファレンス 13.7.2.4 OPTIMIZE TABLE 構文 その他の考慮事項 本番環境ではバイナリログを残さないという選択肢はないかもしれないが、知識として持っておこう。 OPTIMIZE TABLEは使ったことないので別の方法はないか? 別案も考えてみた。 代替案 ダミーテーブルを作っておいて、既存テーブルと差し替え、差し替え後drop tableする。 手順 xxx_tableからxxx_table_newを作る xxx_tableからxxx_table_newへデータを流し込む xxx_table → xxx_table_oldに名前を変える xxx_table_new → xxx_tableに名前を変える 動作確認 xxx_table_oldをdropする 検証 # 全レコード数 (有効なレコード + 論理削除されたレコード) mysql> SELECT COUNT(*) FROM dummy; +----------+ | COUNT(*) | +----------+ | 46882470 | +----------+ 1 row in set (23.86 sec) # 有効なレコード数 mysql> SELECT COUNT(*) FROM dummy WHERE delete_flg = 0; +----------+ | COUNT(*) | +----------+ | 29244002 | +----------+ 1 row in set (1 min 15.16 sec) # 論理削除されたレコード mysql> SELECT COUNT(*) FROM dummy WHERE delete_flg IS NULL; +----------+ | COUNT(*) | +----------+ | 17638468 | +----------+ 1 row in set (1 min 11.63 sec) # 論理削除されているレコードを物理削除 (フラグメンテーションを疑似的につくる) mysql> DELETE FROM dummy WHERE delete_flg IS NULL; Query OK, 17638468 rows affected (36 min 38.17 sec) # 確認 mysql> SELECT -> table_name -> , engine -> , FORMAT(table_rows, 0) AS table_rows -> , FORMAT(avg_row_length, 0) AS avg_row_length -> , FORMAT(data_length, 0) AS data_Byte -> , FORMAT(index_length, 0) AS index_Byte -> , FORMAT(data_free, 0) AS data_free_Byte -> , FORMAT((data_length + index_length + data_free), 0) AS all_Byte -> FROM -> information_schema.tables -> WHERE -> table_schema=database() -> ORDER BY -> (data_length + index_length + data_free) DESC -> LIMIT 1; +--------------------+--------+------------+----------------+---------------+---------------+----------------+----------------+ | table_name | engine | table_rows | avg_row_length | data_Byte | index_Byte | data_free_Byte | all_Byte | +--------------------+--------+------------+----------------+---------------+---------------+----------------+----------------+ | dummy | InnoDB | 29,398,547 | 192 | 5,654,904,832 | 7,365,050,368 | 153,092,096 | 13,173,047,296 | +--------------------+--------+------------+----------------+---------------+---------------+----------------+----------------+ 1 row in set (0.09 sec) # dummy_newを作る mysql> CREATE TABLE dummy_new LIKE dummy; Query OK, 0 rows affected (0.45 sec) # データを流す mysql> INSERT INTO dummy_new SELECT * FROM dummy; Query OK, 29244002 rows affected (1 hour 2 min 59.00 sec) Records: 29244002 Duplicates: 0 Warnings: 0 # ディスク容量を確認 mysql> SELECT -> table_name -> , engine -> , FORMAT(table_rows, 0) AS table_rows -> , FORMAT(avg_row_length, 0) AS avg_row_length -> , FORMAT(data_length, 0) AS data_Byte -> , FORMAT(index_length, 0) AS index_Byte -> , FORMAT(data_free, 0) AS data_free_Byte -> , FORMAT((data_length + index_length + data_free), 0) AS all_Byte -> FROM -> information_schema.tables -> WHERE -> table_schema=database() -> ORDER BY -> (data_length + index_length + data_free) DESC -> LIMIT 2; +------------------------+--------+------------+----------------+---------------+---------------+----------------+----------------+ | table_name | engine | table_rows | avg_row_length | data_Byte | index_Byte | data_free_Byte | all_Byte | +------------------------+--------+------------+----------------+---------------+---------------+----------------+----------------+ | dummy | InnoDB | 29,398,547 | 192 | 5,654,904,832 | 7,365,050,368 | 763,363,328 | 13,783,318,528 | | dummy_new | InnoDB | 29,283,623 | 102 | 3,012,558,848 | 4,084,023,296 | 4,194,304 | 7,100,776,448 | +------------------------+--------+------------+----------------+---------------+---------------+----------------+----------------+ 2 rows in set (0.00 sec) 効果ありそう。 これで効果があるのならば、MySQLdumpしてimportする方法でも効果がありそう。 MySQLのdumpファイルはdrop table -> create table -> insert みたいな流れなので、多分フラグメンテーションを解消できると思う。 どのアプローチを採用するかは各チームで話し合ってください。 バイナリログのサイズを確認する。 確認用SQL バイナリログファイルを一覧表示 SHOW BINARY LOGS; バイナリログを消すためのSQL xxxの1つ手前までのバイナリログを削除する PURGE BINARY LOGS TO 'xxx'; MySQLのリファレンスによると、バイナリログには下記2つの重要な目的がある。 ・レプリケーションについて、マスターレプリケーションサーバー上のバイナリログは、スレーブサーバーに送信されるデータ変更のレコードを提供します。マスターサーバーは、そのバイナリログに格納されているイベントをそのスレーブに送信し、スレーブはこれらのイベントを実行して、マスター上で実行されたものと同じデータ変更を実行します。 ・ある特定のデータリカバリ操作には、バイナリログの使用が必要です。バックアップがリストアされたあと、バックアップが実行されたあとに記録されたバイナリログ内のイベントが再実行されます。これらのイベントは、データベースをバックアップのポイントから最新の状態に持って行きます。 MySQLリファレンス 5.2.4 バイナリログ そのため、削除に関しては慎重に判断しましょう。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Equalumにkafkaを繋げてみる(実行編)

今回はいよいよEqualumに接続します 前回は、準備編としてMBP上にkafka環境を導入し、Pythonを使った検証ツールを作成し、kafka上での動作確認までを行いました。今回はいよいよ具体的にkafkaのプロデューサに送りこまれたメッセージを、JSON形式に整えてEqualumの上流側データソースとして接続してみたいと思います。 まずは、受け側の準備 Equalumを通して受け取る側のデータソースを準備したいと思います。今回はMySQLをDocker上で動かして、この環境上に事前展開したテーブルに向かって、JSON形式をEqualumが通常のRDB系カラム情報に変換し、シンプルに連続して挿入処理を行う形にします。 MySQL側のテーブルを作る 基本的には、今までのパターンを修正して「サクッと!」準備してしまいます。 # coding: utf-8 # # MySQL側のテーブル作成 # # Python 3版 # # # 初期設定 import sys stdout = sys.stdout sys.stdout = stdout import pymysql.cursors # 作成するテーブル名 Table_Name = "kafka_TGT_Table" # テーブル初期化 Table_Init = "DROP TABLE IF EXISTS " # テーブル定義 DC0 = "ts_key VARCHAR(30) PRIMARY KEY, " DC1 = "xx INT, yy INT " try: print("TGTテーブル作成処理を開始") # デモ用のテーブルの作成 Table_Create = "CREATE TABLE IF NOT EXISTS " + Table_Name + " (" + DC0 + DC1 + ")" # MySQLとの接続 db = pymysql.connect(host = 'localhost', port=xxxx, user='xxxxxx', password='xxxxxxxxx', db='xxxxx', charset='utf8mb4', cursorclass=pymysql.cursors.DictCursor) with db.cursor() as cursor: # 既存テーブルの初期化 cursor.execute(Table_Init + Table_Name) db.commit() # 新規にテーブルを作成 cursor.execute(Table_Create) db.commit() except KeyboardInterrupt: print('!!!!! 割り込み発生 !!!!!') finally: # データベースコネクションを閉じる db.close() print("TGTテーブル作成処理が終了") 検証用のトピックを作る 今回の検証に使うトピックを作ります。コマンドは前回の形式(最小構成なのでパーティション等は1個で対応します)で実行し、名前はTPC4JSONとします。 % kafka-topics --create --zookeeper localhost:2181 --replication-factor 1 --partitions 1 --topic TPC4JSON Equalumの設定の際に、プレビューを使って説明したいので「テストを兼ねてコンシューマ側に向かって」少しデータを作成しておきます。このテスト分はEqualumが繋がったタイミングで「初期抽出」が自動的に行われます。コンソールを見ながら10個程度有れば十分なので、適当なタイミングで切り上げればOKです。 プロデューサ側の入力 {'id': '2021/04/11-08:18:59:171423', 'x': -1399, 'y': 85} {'id': '2021/04/11-08:19:00:304312', 'x': -791, 'y': 476} {'id': '2021/04/11-08:19:01:309313', 'x': -1001, 'y': 508} ///////// 途中省略 ////////// {'id': '2021/04/11-08:19:12:382028', 'x': 544, 'y': 200} {'id': '2021/04/11-08:19:13:389613', 'x': 518, 'y': 205} コンシューマ側の出力 読み出したデータ   1個目 Data ID: 2021/04/11-08:18:59:171423 Data X: -1399 Data Y: 85 読み出したデータ   2個目 Data ID: 2021/04/11-08:19:00:304312 Data X: -791 Data Y: 476 読み出したデータ   3個目 Data ID: 2021/04/11-08:19:01:309313 Data X: -1001 Data Y: 508 //////// 途中省略 //////// 読み出したデータ   14個目 Data ID: 2021/04/11-08:19:12:382028 Data X: 544 Data Y: 200 読み出したデータ   15個目 Data ID: 2021/04/11-08:19:13:389613 Data X: 518 Data Y: 205 !!!!! 割り込み発生 !!!!! 疎通が確認出来ましたので、いよいよ検証の本番に移ります。 Equalumの設定 次にEqualumの設定を行って行きます。 kafkaの接続も、基本的には他のデータソースと同じ様にGUIベースの設定項目を埋めて行く作業になります。 (1)ダッシュボードのSOURCES項目にある+ADDボタンを選択 (2)kafkaを選択 (3)必要事項を設定 今回はオールインワンなのでBrokers Listは1個だけ「IPアドレス:ポート番号」で設定しました。 (4)設定したソースにトピックを登録 (4−1)ダッシュボードに先程のkafkaが登録されたら、そのソースを選択してトピックを登録します。 Streamsの右側にある+ADDボタンを選択して、表示されるGUI上で必要な項目を設定します。先程のソース登録が正常に行われていると、Source Topicの所でプルダウンメニューが出てきて、事前に登録されたトピックが選択可能になっています。 File format optionsのプルダウンメニューからJSONを選択します。 JSON Schema File Optionsの項目にあるSchema Fileの設定部分でGenerateを選択します。前もって正しい内容のファイルが有れば此処でアップロードする事も可能ですが、今回はEqualum任せでサクッと!前に進める事にします。 次にTag Name to Eventを設定します。今回はシンプルな形式ですので、デフォルトの/rootを選択しました。 最後にAdvanced Settingsの中にあるUser-Defined Primary Keyを設定(今回はidを選択)しておきます。 此処までの作業で、kafkaとEqualumの接続設定は終了になります。 設定後にすぐに初期抽出の処理が行われ、下流側の設定が済み次第処理が実行されます(デフォルトでは、初期抽出がONになっています)。またこの処理準備により、実際のFLOWデザインの際に実際のデータをシュミレートした作業が出来る様になりますので、途中に組み込む処理によっては、設定した処理の結果が即確認出来る等の便利機能になっています。 (5)FLOWの作成 次にFLOWの作成を行います。今回はデータ自体が超シンプルなので、間の処理は省略した形(ある意味レプリケーションになりますが)で検証を行います。Equalum的には、正常に接続されたデータは、FLOWの中においては全て操作対象になりますので、JSONの項目にルックアップ情報を埋め込み、それをFLOWの中で抽出・参照・置き換えといった作業等も他のデータソース同様に簡単に行えます。 ダッシュボードのFLOWS右側にある+ADDボタンを選択します。 (5−1)FLOWデザイン上でマウスのダブルクリックを行い、上流側のデータソースを選択します。 (5−2)同様にFLOWデザイン上でマウスのダブルクリックを行い、下流側のデータソースを選択します。 (5−3)FLOWデザイン上で両者を関連付けます。 此処で、最初に動作確認で生成したJSONデータの状況を確認するには、上流側のPreviewを選択します。 無事にカラム属性を含めて処理対象になっている事が確認出来ました。 (5−4)ターゲット側のマッピングを行います。 Equalumの柔軟性の一つに、この最終段でのカラム項目のマッピング機能が有ります。この段階で上流側から流れてくるデータを送らない設定も出来ますし、途中で派生させたカラムに対するデータ適用なども行えます(ルックアップ処理などで便利)。 Editボタンを選択して設定GUIを呼び出します。今回は必要項目だけを設定して検証作業を行います。 データベースとテーブルを選択します。 +MAPPINGボタンを選択します。 Target Mappingの部分を適切に選択・設定します。 問題がなければOKボタンを選択して設定を終了します。 この状況まで来れば、あとは以前の検証で行った作業と同じですので、FLOWをセーブして配備・実行するだけです。 これで準備が整いました。 では検証開始! 今回の検証は、画面上のマウス座標をPythonで抽出し、シンプルで小規模のJSON形式でプロデューサに送出する形で行った関係上、利き腕の労力が半端ない状況でしたので、あまり長時間のデータ生成は出来ませんでした。。。(汗) 以下は、検証作業時のEqualumダッシュボードの状況になります。 以下は、今回の検証結果データになります(左側はMySQLに格納されたデータ、右側がkafkaのプロデューサへの送出データになります) 2021/04/11-09:37:58:330350| 527|223| {'id': '2021/04/11-09:37:58:330350', 'x': 527, 'y': 223} 2021/04/11-09:37:59:335195| -993| 62| {'id': '2021/04/11-09:37:59:335195', 'x': -993, 'y': 62} 2021/04/11-09:38:00:341232| 1059| 0| {'id': '2021/04/11-09:38:00:341232', 'x': 1059, 'y': 0} 2021/04/11-09:38:01:347066| 1350| 69| {'id': '2021/04/11-09:38:01:347066', 'x': 1350, 'y': 69} /////// 途中省略 ////// 2021/04/11-09:38:11:412048| -911|229| {'id': '2021/04/11-09:38:11:412048', 'x': -911, 'y': 229} 2021/04/11-09:38:12:419794| -509|212| {'id': '2021/04/11-09:38:12:419794', 'x': -509, 'y': 212} 2021/04/11-09:38:13:425034| -272|246| {'id': '2021/04/11-09:38:13:425034', 'x': -272, 'y': 246} 2021/04/11-09:38:14:429277| -586|248| {'id': '2021/04/11-09:38:14:429277', 'x': -586, 'y': 248} /////// 途中省略 ////// 2021/04/11-09:38:30:523297|-1037|482| {'id': '2021/04/11-09:38:30:523297', 'x': -1037, 'y': 482} 2021/04/11-09:38:31:528702| -333|641| {'id': '2021/04/11-09:38:31:528702', 'x': -333, 'y': 641} 2021/04/11-09:38:32:535799|-1228|316| {'id': '2021/04/11-09:38:32:535799', 'x': -1228, 'y': 316} 2021/04/11-09:38:33:544202|-1110|690| {'id': '2021/04/11-09:38:33:544202', 'x': -1110, 'y': 690} 2021/04/11-09:38:34:550620| -990|197| {'id': '2021/04/11-09:38:34:550620', 'x': -990, 'y': 197} /////// 途中省略 ////// 2021/04/11-09:38:51:646299| -823|456| {'id': '2021/04/11-09:38:51:646299', 'x': -823, 'y': 456} 2021/04/11-09:38:52:655003|-1196|438| {'id': '2021/04/11-09:38:52:655003', 'x': -1196, 'y': 438} 2021/04/11-09:38:53:662194| -624|305| {'id': '2021/04/11-09:38:53:662194', 'x': -624, 'y': 305} 2021/04/11-09:38:54:668645| -242|568| {'id': '2021/04/11-09:38:54:668645', 'x': -242, 'y': 568} 2021/04/11-09:38:55:674050| -328|163| {'id': '2021/04/11-09:38:55:674050', 'x': -328, 'y': 163} 2021/04/11-09:38:56:678265|-1332|646| {'id': '2021/04/11-09:38:56:678265', 'x': -1332, 'y': 646} /////// 途中省略 ////// 2021/04/11-09:39:14:792023| 935| 55| {'id': '2021/04/11-09:39:14:792023', 'x': 935, 'y': 55} 2021/04/11-09:39:15:794852| 1116| 49| {'id': '2021/04/11-09:39:15:794852', 'x': 1116, 'y': 49} 2021/04/11-09:39:16:798872| 557|121| {'id': '2021/04/11-09:39:16:798872', 'x': 557, 'y': 121} 2021/04/11-09:39:17:804355| 637|199| {'id': '2021/04/11-09:39:17:804355', 'x': 637, 'y': 199} 無事にストリーミング出来た様です。 今回のまとめ 今回は、前回に引き続きEqualumのストリーミング検証として、データソースにkafkaを使った場合の検証作業を行いました。Equalumは、仕組みの総力戦で効率的且つ即時的な「Exactly Once」を実現し、CDCストリーミング対象のリレーショナル・データベース系に加えて、今回検証したkafkaにもこの機能を適用させています。これは、昨今のIoT系データ処理の仕組みを構築する際に、周辺の既存業務系やエッジ展開しているデータベース群等とも、極めて有機的で能動的なデータ連携の可能性を提供出来る事を示しています。 もちろん、データは企業・団体活動の重要なエビデンスであり、その量・質を高める作業こそが日常の業務・課題であると言えるでしょう。そしてそれらを強固に守るという事も重要なITの役割だと言えますが、変化の激しい・不確定性の高い現代社会において、常時接続時代、5Gを始めとする低遅延・高速な次世代通信、全てがネットに繋がるコネクテッドXの流れが、それらのより良いデータを創る重要な資源として、多様なデータの利活用戦略や具体的な方法論・実装を要求してきています。 その新たなデータ・セントリックな時代における、データ・オプス(DataOps)の核として、Equalumは色々なシチュエーションの中で、確実に前に進めるソリューションなのかもしれません。 データの質や量・扱う時間に関係なく 情け容赦の無い、創造的で革新的なデータ利活用し データを再生可能エネルギー(資源)として、より良い結果(データ)の創造を行う それらを支えるデータ流通革命の一端を、Equalumは十分に担えると一連の検証を通じて感じました。 最近、国内でも正式に2社の外販代理店が立ち上がるという話も聞こえておりますので、また別の機会に「小ネタ的な」検証を行って皆様と共有させて頂きたいと考えております。 謝辞 本検証は、Equalum社の最新公式バージョン(V2.24)を利用して実施しています。この貴重な機会を提供して頂いたEqualum社に対して感謝の意を表すると共に、本内容とEqualum社の公式ホームページで公開されている内容等が異なる場合は、Equalum社の情報が優先する事をご了解ください。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Equalumにkafkaを繋げてみる(準備編)

以前に書いたEqualum検証の続き・・・・ 前に投稿したEqualumの検証で、kafkaを上流側データソースとして使えないのか?・・・なるご質問を頂くケースが結構有りましたので、今回は簡単なkafka環境との接続検証を行ってみたいと思います。 まずはkafka環境の構築 ハードウエアを正式に用意して、保守本流・王道のkafka環境を構築する・・という方向性も有るのですが、今回は普段使いのMBPの上にサラッとkafka環境を構築して、その環境に対してPythonで作ったスクリプトでメッセージを投げ、そのメッセージをEqualumが受け取って必要な処理(今回はメッセージの分解とカラム化を行います)をFLOWで作成し、ターゲットとして同じMBP上で動いているDocker環境で稼働しているMySQLに着地させてみることにします。 事前の言い訳・・・m(_ _)m(苦笑) kafka周辺の技術情報は、既に多くの諸先輩方がQiita、その他の記事として公開されていますので、それらの記事を是非!参考にして見てください。今回の検証は、あくまでも動くかどうかを確認する・・という部分で戦略的妥協をしております(汗)。。。 また、今回は紙面の都合上・・kafka周りの準備までになります(Equalumとの連携は次回を予定)ので、その辺は何卒ご理解頂きたく・・・ まず最初にbrew環境の導入(導入済みの場合不要です) Mac環境へhomebrewをインストールします。 kafkaのインストール(zookeeperも一緒にインストールされます) % brew install kafka kafkaを起動してみます 無事にインストールが出来れば、環境を立ち上げてみましょう。 % brew services start zookeeper % brew services start kafka zookeeper は localhost:2181, kafka は localhost:9092 で起動します(標準設定) また、環境設定のファイルは/usr/local/etc/kafka/server.propertiesに有ると思いますので、取り急ぎトピックを削除出来るように設定を変更しておきます(最初、コマンドで試験的に作った幾つかのトピックを、初期化&リソースを解放しようと削除していたのですが、コマンドを使って既存リストを見ると永久不滅のトピック状態で、あれ?・・・という事で探し当てた設定になります・・・ご参考まで) delete.topic.enable=true この設定をファイルに加えてから、環境を再起動します。起動中の環境を止める場合は % brew services stop kafka % brew services stop zookeeper を行います。 本格的にkafkaを弄ってみる まずは、検証に使うトピックを作成します。 % kafka-topics --create --zookeeper localhost:2181 --replication-factor 1 --partitions 1 --topic XXXXX 

 中パラメータは全て必要みたいなので、このままコピペで使って最後のトピック名だけ適宜変更します 因みに・・・・ * --create でトピックの作成 * --zookeeper localhost:2181 で zookeeper の LISTEN アドレスの指定 * --replication-factor 1 でレプリカを 1 つのみ生成 * --partitions 1 でパーティションを 1 つのみ生成 * --topic でトピック名を指定 です 今回は、MBPの資源保護の観点から最小構成で設定しました。 トピック周りの処理について 環境が起動して、取り急ぎのトピックを作成したらリストで表示してみます。 % kafka-topics --list --zookeeper localhost:2181 また、初期化等を行う場合は、kafkaの作法に従って(?)トピック自体を削除・初期化する必要が有りますので、以下のコマンドで処理を行います。(前述の設定をお忘れなく・・・) % kafka-topics --delete --zookeeper localhost:2181 --topic XXXXXXX 今回の検証では使いませんが、コマンド処理で弄る場合の参考として・・・ プロデューサーを起動する場合は、以下のコマンドで処理を行います。 % kafka-console-producer --broker-list localhost:9092 --topic XXXXXXX 同様にコンシューマの起動は、少し長めになりますが % kafka-console-consumer --bootstrap-server localhost:9092 --topic XXXXXXX --from-beginning でメッセージ待受状態になりますので、双方が起動している状態で適当な文字列を入力して、リターンキーを押す事にコンシューマ側のコンソールに入力された文字列がメッセージとして表示されると思います。 では、検証用のPythonを書きます 今回の検証では、Pythonのモジュールを使って(pyautogui)画面上のマウス座標を取得し、その情報と識別情報としてタイムスタンプ的な情報を組み合わせ、JSON形式でEqualumを通過させたいと思います。ネット上には諸先輩方の歴戦の苦労の賜物が沢山公開されておりますので、それらを参考にして頂けば、さほど難しくなく「取り敢えず動く=動きを作る(動作する)」版は作れるかと思います。今回作成して検証に使ったスクリプトは以下の通りです。 # # Equalumのkafka接続検証 # # プロデューサ側の処理(JSON形式でメッセージを送信) # from kafka import KafkaProducer import pyautogui import time import json try: # 変数の初期化 Counter = 1 TimeOut = 60 Sleep = 1 # プロデューサーとの接続処理 producer = KafkaProducer(bootstrap_servers='localhost:9092', value_serializer=lambda m: json.dumps(m).encode('utf-8'))    #安易ですが、無限ループで処理します。 while True: # 日付情報と時間情報の取得 from datetime import datetime messageId = datetime.now().strftime("%Y/%m/%d-%H:%M:%S:%f") # JSON形式にメッセージを作成 kafka_msg = {"id" : messageId, "x" : pyautogui.position().x, "y" : pyautogui.position().y} print(kafka_msg) # プロデューサーにメッセージを送る result = producer.send('JSON', kafka_msg).get(timeout=TimeOut) #print(result) time.sleep(Sleep) Counter = Counter + 1 except KeyboardInterrupt: print('!!!!! 割り込み発生 !!!!!') finally: print ("処理の終了") print(str(Counter) + "回の処理を実行しました") Equalumに接続する前に、取り急ぎMBP上で立ち上げたkafka環境を通してみたいと思います。 トピック名をJSONとして先程のコマンドで作成しておきます。 データが届いているかを確認するために、コンシューマ側の仕組みを用意する 今回は、取り急ぎの動作検証ですので、以下のスクリプトで受信状況を確認します。 # # Equalumのkafka接続検証 # # コンシューマ側の処理 # from kafka import KafkaConsumer import sys import json try: # 変数の初期化 Counter = 1 # コンシューマに接続する consumer = KafkaConsumer(bootstrap_servers='localhost:9092', auto_offset_reset='latest',value_deserializer=lambda m: json.loads(m.decode('utf-8'))) consumer.subscribe(['JSON']) for message in consumer: print("コンシューマ側に送られてきたJSONメッセージ : " + message) print("\n読み出したデータ\n") print("Data ID:",message[6]['id']) print("Data X:",message[6]['x']) print("Data Y:",message[6]['y']) Counter = Counter + 1 # Terminate the script sys.exit() except KeyboardInterrupt: print('!!!!! 割り込み発生 !!!!!') finally: print ("処理の終了") print(str(Counter) + "回の処理を実行しました") 準備が出来たら動作確認します 両方のスクリプトを起動して、画面上でマウスを「心のままに」動かすと、1秒間隔でデータを取り込んでくれます。動作状況は双方のコンソールに出力されるようになっていますので、その結果を確認して問題が無い様で有れば、いよいよEqualumを経由させてMySQLに着地させる事になります。 コンシューマ側の出力 コンシューマ側に送られてきたメッセージ :  ConsumerRecord(topic='JSON', partition=0, offset=137, timestamp=1618055496288, timestamp_type=0, key=None, value={'id': '2021/04/10-20:51:36:287301', 'x': 910, 'y': 454}, headers=[], checksum=None, serialized_key_size=-1, serialized_value_size=56, serialized_header_size=-1) 読み出したデータ Data ID: 2021/04/10-20:51:36:287301 Data X: 910 Data Y: 454 ////// 途中省略 ////////// コンシューマ側に送られてきたメッセージ :  ConsumerRecord(topic='JSON', partition=0, offset=146, timestamp=1618055505336, timestamp_type=0, key=None, value={'id': '2021/04/10-20:51:45:335406', 'x': 701, 'y': 253}, headers=[], checksum=None, serialized_key_size=-1, serialized_value_size=56, serialized_header_size=-1) 読み出したデータ Data ID: 2021/04/10-20:51:45:335406 Data X: 701 Data Y: 253 !!!!! 割り込み発生 !!!!! 処理の終了 11回の処理を実行しました プロデューサ側の入力 {'id': '2021/04/10-20:51:36:287301', 'x': 910, 'y': 454} {'id': '2021/04/10-20:51:37:293747', 'x': 905, 'y': 458} //////// 途中省略 ///////// {'id': '2021/04/10-20:51:44:327730', 'x': 605, 'y': 254} {'id': '2021/04/10-20:51:45:335406', 'x': 701, 'y': 253} 今回のまとめ 今回は、Equalumの上流側データソースとして、kafkaを繋げるための前準備を行いました。Equalum社の製品・開発のVP、CTOとやりとりをさせてもらった際に、RDB系のCDC版Exactly Onceだけではなくて、kafkaを上流に設定した場合も、Equalum以降では、Exactly Onceを同じ様にサポート出来る・・との事でした。また、幾つかのパターンに分けてこの可能性を考えてみると、 技術的なユースケースの観点から: Kafka-> Equalum-> RDBMS このパターンは通常、アプリケーション統合等に使用されるパターンで、アプリケーションの特定のイベントがKafkaへの書き込みをトリガーし、Equalumがこのイベントを読み取って必要な変換/エンリッチメントなどを行い、そのデータを2番目のデータベースに速やか且つ確実プッシュする事が出来ます。 Kafka-> Equalum-> Kafka このパターンも前述同様に、かなりの頻度でアプリケーション統合に使用されており、アプリケーションの特定のイベントがKafkaへの書き込みをトリガーし、Equalumはこのイベントを読み取って、前述同様に必要な変換/エンリッチメントなどを実行(この部分は、EqualumのGUIで行いますので、皆様が既に暗記されている「Noコード」の恩恵を受ける事が可能です)し、変換されたイベントを別のKafkaトピックにプッシュして、他のアプリケーションでさらに処理を続行する事になります。(戦略的にkafkaの途中処理に柔軟な介入を可能とする事で、新しいkafkaの可能性が出てくる使い方になるかと) RDBMS-> Equalum-> Kafka このパターンは、「イベント生成」または「イベントソーシング」と呼ばれる使い方で、EqualumはデータベースからCDCイベントを読み取り、必要に応じてデータを変換し、誰でも簡単に利用できるように前準備を提供してから、当該イベントをKafkaトピックに公開し、処理を継続していきます。既存のデータベース情報を速やか&確実にkafkaのパイプに提供出来ますので(FLOWの部分は前述同様の「Noコード」で)面白い使い方が可能になるかと思います。 等が出てきますので、最近良く話を聞く「xxOps」的なシステム活用を「データ流通」の側面で大きくサポート出来る可能性が有ると思います。 次回は・・・ 次回は、今回の環境を活用していよいよEqualumを間に入れて、ターゲット・データソースとしてMySQLに「Exactly Once」で着地させてみたいと思います。 謝辞 本検証は、Equalum社の最新公式バージョン(V2.24)を利用して実施しています。この貴重な機会を提供して頂いたEqualum社に対して感謝の意を表すると共に、本内容とEqualum社の公式ホームページで公開されている内容等が異なる場合は、Equalum社の情報が優先する事をご了解ください。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rails6/Docker/MySQL + Elasticsearch 環境構築

はじめに Elasticsearchを触りたいと思ったのだが、Dockerでの環境構築で詰まったので今後のためにメモ。 環境 Rails6・Docker・MySQLによる環境構築 自分の備忘録用に書いたものだが、ここに+elasticsearchを加えていく。 以下のファイル内のmyappは自分が作成したディレクトリ名に置き換える(今回はelasticsearch-railsと命名) Dockerfile FROM ruby:2.7.1 RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - \ && echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list # myappを自分のアプリ名に変更 RUN apt-get update -qq && apt-get install -y nodejs yarn RUN mkdir /elasticsearch-rails WORKDIR /elasticsearch-rails COPY Gemfile /elasticsearch-rails/Gemfile COPY Gemfile.lock /elasticsearch-rails/Gemfile.lock RUN bundle install COPY . /elasticsearch-rails # Add a script to be executed every time the container starts. COPY entrypoint.sh /usr/bin/ RUN chmod +x /usr/bin/entrypoint.sh ENTRYPOINT ["entrypoint.sh"] EXPOSE 3000 # Start the main process. CMD ["rails", "server", "-b", "0.0.0.0"] Gemfile source 'https://rubygems.org' gem 'rails', '6.0.3' Gemfile.lock # 空のままで entrypoint.sh #!/bin/bash set -e # Remove a potentially pre-existing server.pid for Rails. rm -f /myapp/tmp/pids/server.pid # Then exec the container's main process (what's set as CMD in the Dockerfile). exec "$@" docker-compose.yml version: "3" services: # Elasticsearch用のコンテナ elasticsearch: # 下の1行でも環境構築は出来るが、日本語を扱うときに必要なプラグイン(kuromoji)を入れるために、 # elasticsearch用のDockerfileを作成 # image: docker.elastic.co/elasticsearch/elasticsearch:7.10.1 build: context: . dockerfile: Dockerfile-elasticsearch environment: - discovery.type=single-node - cluster.name=docker-cluster - bootstrap.memory_lock=true - "ES_JAVA_OPTS=-Xms512m -Xmx512m" ulimits: memlock: soft: -1 hard: -1 ports: - 9200:9200 volumes: - esdata:/usr/share/elasticsearch/data # Kibana用のコンテナ kibana: # elasticsearchとkibanaのimageのバージョン番号を一致 image: docker.elastic.co/kibana/kibana:7.10.1 ports: - 5601:5601 depends_on: - elasticsearch db: image: mysql:8.0 environment: MYSQL_ROOT_PASSWORD: password ports: - '3306:3306' command: --default-authentication-plugin=mysql_native_password volumes: - mysql-data:/var/lib/mysql web: build: . command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'" volumes: # myappを自分のアプリ名に変更 - .:/elasticsearch-rails ports: - "3000:3000" depends_on: - db # elasticsearchのコンテナと関連づける - elasticsearch stdin_open: true tty: true volumes: esdata: mysql-data: elasticsearchとKibanaを追加したので所々変更。 rials用のコンテナ(web)のdepends_onに、elasticsearchのコンテナ名を追加するのを忘れないように Dockerfild-elasticsearch FROM docker.elastic.co/elasticsearch/elasticsearch:7.10.1 # 日本語をあつかうときに使うプラグイン RUN bin/elasticsearch-plugin install analysis-kuromoji # 国際的に規約されてる文字の解析器 RUN bin/elasticsearch-plugin install analysis-icu アプリ作成 --database=mysqlを忘れると、 config/database.ymlのadapterがmysql2ではなくsqliteになってしまったので注意 --force:「強制的に」と言う意味 --no-deps:リンクされたコンテナを起動しない --skip-test:minitestの作成を防ぐ。 --api:APIモードでRailsプロジェクトを作成し、APIには不要なView・UI関連のライブラリがインストールされない。 --webpacker:webpacker をインストール docker-compose run web rails new . --force --no-deps --database=mysql --webpacker 私の場合、ここで下のエラーが発生 response from daemon: OCI runtime create failed: container_linux.go:345: starting container process caused "exec: \"rails\": executable file not found in $PATH": unknown ここでbuildしたら治るとのことだったので実行。 docker-compose build 詳しいことは分かっていないが解決したので、仕切り直して先に進める docker-compose run web rails new . --force --no-deps --database=mysql --webpacker docker-compose build config/databas.yml変更 config/database.yml default: &default adapter: mysql2 encoding: utf8mb4 pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> username: <%= ENV.fetch("MYSQL_USERNAME", "root") %> password: <%= ENV.fetch("MYSQL_PASSWORD", "password") %> host: <%= ENV.fetch("MYSQL_HOST", "db") %> development: <<: *default database: elasticsearch_rails_development test: <<: *default database: elasticsearch_rails_test production: <<: *default database: elasticsearch_rails_production username: elasticsearch_rails password: <%= ENV['ELASTICSEARCH_RAILS_DATABASE_PASSWORD'] %> DBを作成する docker-compose run --rm web bundle exec rails db:create 起動し、動作確認する docker-compose build docker-compose up Rails確認 http://localhost:3000 にアクセスして、お馴染みの画面が出ればOK Kibana確認 http://localhost:5601 にアクセスし、ページが表示されればOK Elasticsearch確認 Curlコマンドでリクエストを投げ、下記のようなクラスタやバージョン情報が含まれるレスポンス返ってくればOK $ curl -XGET http://localhost:9200/ { "name" : "7d712c1f3298", "cluster_name" : "docker-cluster", "cluster_uuid" : "fA4Th3p8RNqMzyJxUlwrYw", "version" : { "number" : "7.10.1", "build_flavor" : "default", "build_type" : "docker", "build_hash" : "1c34507e66d7db1211f66f3513706fdf548736aa", "build_date" : "2020-12-05T01:00:33.671820Z", "build_snapshot" : false, "lucene_version" : "8.7.0", "minimum_wire_compatibility_version" : "6.8.0", "minimum_index_compatibility_version" : "6.0.0-beta1" }, "tagline" : "You Know, for Search" } 参考記事 DockerでRails,Postgres,ElasticSearchの開発環境を構築する方法 docker環境でのRailsアプリの立ち上げ RailsとElasticsearchで検索機能をつくり色々試してみる - その1:サンプルアプリケーションの作成 おわりに 毎度毎度環境構築で詰まりますね(ーー;)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails】Useridがnilになったとき

環境 Rails 6.1.3.1 Ruby 3.0.0 MySQL 8.0.23 エラー内容 Rails consoleで新しいユーザーを作成したときのこと、 irb(main):001:0> User.create(name: "hogege",email: "hoge@hoge",password: "password",password_confirmation: "password") TRANSACTION (0.2ms) BEGIN User Exists? (0.7ms) SELECT 1 AS one FROM `users` WHERE `users`.`email` = 'hoge@hoge' LIMIT 1 TRANSACTION (0.2ms) ROLLBACK => #<User id: nil, name: "hogege", email: "hoge@hoge", created_at: nil, updated_at: nil, password_digest: [FILTERED]> Userid, created_at, update_atがnilになってしまいました +-----------------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-----------------+--------------+------+-----+---------+----------------+ | id | bigint | NO | PRI | NULL | auto_increment | | name | varchar(255) | YES | | NULL | | | email | varchar(255) | YES | UNI | NULL | | | created_at | datetime(6) | NO | | NULL | | | updated_at | datetime(6) | NO | | NULL | | | password_digest | varchar(255) | YES | | NULL | | +-----------------+--------------+------+-----+---------+----------------+ 確認してみても、idはauto_increaseになっているので、create!を使ってみる irb(main):002:0> User.create!(name: "hogege",email: "hoge@hoge",password: "password",password_confirmation: "password") TRANSACTION (6.7ms) BEGIN User Exists? (4.3ms) SELECT 1 AS one FROM `users` WHERE `users`.`email` = 'hoge2@hoge' LIMIT 1 TRANSACTION (1.9ms) ROLLBACK Traceback (most recent call last): 1: from (irb):7:in `<main>' ActiveRecord::RecordInvalid (Validation failed: Email is invalid) なんてことはない話でした。emailの形式が間違っていました、、、 irb(main):008:0> User.create(name: "hogege2",email: "hoge2@hoge.com",password: "password",password_confirmation: "password") TRANSACTION (0.2ms) BEGIN User Exists? (1.5ms) SELECT 1 AS one FROM `users` WHERE `users`.`email` = 'hoge2@hoge.com' LIMIT 1 User Create (1.5ms) INSERT INTO `users` (`name`, `email`, `created_at`, `updated_at`, `password_digest`) VALUES ('hogege2', 'hoge2@hoge.com', '2021-04-11 00:45:14.108385', '2021-04-11 00:45:14.108385', '$2a$12$g5Ks0L4Eiw.QotTeTzt2ieBsTNKBbrpJiNtb6C/JxERBqmus7UD7q') TRANSACTION (1.9ms) COMMIT => #<User id: 1, name: "hogege2", email: "hoge2@hoge.com", created_at: "2021-04-11 00:45:14.108385000 +0000", updated_at: "2021-04-11 00:45:14.108385000 +0000", password_digest: [FILTERED]> 無事成功! まとめ create 失敗しているときは何も教えてくれず終わり create! エラー内容を教えてくれる
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Docker環境構築[Django+Nginx+MySQL]

構成 root ├── docker-compose.yml ├── mysql ├── sql ├── nginx │ ├── conf │ │ └── app_nginx.conf │ └── uwsgi_params └── python ├── Dockerfile └── requirements.txt Django Dockerfile FROM python:3.9 #バッファが溜まってから出力するのを避ける ENV PYTHONUNBUFFERED 1 RUN mkdir /code WORKDIR /code COPY requirements.txt /code/ RUN pip install --upgrade pip && pip install -r requirements.txt COPY . /code/ requirements.txt Django~=3.2 uwsgi PyMySQL django-environ uWSGIの設定 uwsgi_param QUERY_STRING $query_string; uwsgi_param REQUEST_METHOD $request_method; uwsgi_param CONTENT_TYPE $content_type; uwsgi_param CONTENT_LENGTH $content_length; uwsgi_param REQUEST_URI $request_uri; uwsgi_param PATH_INFO $document_uri; uwsgi_param DOCUMENT_ROOT $document_root; uwsgi_param SERVER_PROTOCOL $server_protocol; uwsgi_param REQUEST_SCHEME $scheme; uwsgi_param HTTPS $https if_not_empty; uwsgi_param REMOTE_ADDR $remote_addr; uwsgi_param REMOTE_PORT $remote_port; uwsgi_param SERVER_PORT $server_port; uwsgi_param SERVER_NAME $server_name; Nginxの設定 app_nginx.conf upstream django { ip_hash; server python:8001; } server { listen 8000; server_name 127.0.0.1; charset utf-8; location /static { alias /static; } location / { uwsgi_pass django; include /etc/nginx/uwsgi_params; } } server_tokens off; docker-composeの設定 docker-compose.yml version: '3' services: nginx: image: nginx:1.13 ports: - "8000:8000" volumes: - ./nginx/conf:/etc/nginx/conf.d - ./nginx/uwsgi_params:/etc/nginx/uwsgi_params - ./static:/static depends_on: - python db: image: mysql:5.7 command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci ports: - "3306:3306" environment: MYSQL_ROOT_PASSWORD: root MYSQL_DATABASE: todoList MYSQL_USER: user MYSQL_PASSWORD: password TZ: 'Asia/Tokyo' volumes: - ./mysql:/var/lib/mysql - ./sql:/docker-entrypoint-initdb.d python: build: ./python command: uwsgi --socket :8001 --module app.wsgi --py-autoreload 1 --logto /tmp/mylog.log volumes: - ./src:/code - ./static:/static expose: - "8001" depends_on: - db MySQLの設定 sql/init.sql GRANT ALL PRIVILEGES ON test_todoList.* TO 'user'@'%'; FLUSH PRIVILEGES; プロジェクトの作成 terminal % docker-compose run python django-admin.py startproject app . DB設定 settings.py import os import pymysql # connect mysql pymysql.install_as_MySQLdb() DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'todoList', 'USER': 'user', 'PASSWORD': 'password', 'HOST': 'db', 'PORT': '3306', } } Migration terminal % docker-compose run python ./manage.py makemigrations % docker-compose run python ./manage.py migrate terminal % docker-compose up -d CSS適用 settings.py STATIC_URL = '/static/' STATIC_ROOT = '/static' terminal % docker-compose run python ./manage.py collectstatic *注意 git管理する際は、MySQLの中身をオープンにするのはセキュリティ的によろしくないので.gitignoreに下記を追加しておきましょう。 mysql/* 参照
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む