- 投稿日:2019-04-11T23:25:50+09:00
初心者teamlabのオンラインスキルアップ課題step1をやってみた(コード初心者向け記事)
dockerって何とか、DBとの連携でコード上で具体的にどうするのとか、初心者的にはイメージがつかないほど良くわからないので、teamlabさんのオンラインスキルアップ課題をやってみた。
こちらから課題にアクセスします。
STEP1の内容は下記のようになっています。
- インターネットのしくみ
- WEBサーバについて
- HTMLとCSSについて 4-a. 【Windows】Dockerと開発環境の作り方 4-b. 【Mac】Dockerと開発環境の作り方
- PHPを書いてみる
- PHPでGET/POSTをやってみる
- データベースについて
- SQLを書いてみる
- PHPでデータベースを操作してみる
- 10. GitとGitHubについて
4-b:【Mac】Dockerと開発環境の作り方
1,2,3はわかった気になってとりあえず進めて、まずは4のDockerのセットアップから入ります。
docker-compose -vdockerがちゃんとインストールされているか上記のコマンドで確かめます。
docker-compose up -dteamlabさんのサイトからダウンロードしたフォルダに遷移して、上のコマンドを叩くとコンテナを作成して、起動します。
※Dockerのコマンドに関してはこちら
なんかいろいろエラーは起きたのですが、無事?doneになっています。
「skillup-php-step1-master」をダウンロードして解凍したフォルダに移動したいけど移動できない!っていう場合にですが、フォルダさえ探せれば、フォルダごとターミナルに落としてあげることでpathが表示されるので、あとは先頭にcdつけるだけでフォルダに移動できるはずです。1-6:PHPでGET/POSTをやってみる
1-5は普通にコピペでコード貼って、Dockerで立ち上げたlocalhostにアクセスするだけなので、はしおります。
まず、エディターがない人は適当なエディターをインストールしてください。
(ぼくはsublimeをつかっています。)とりあえず、課題のpostだけやってみました
index.html1
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>POSTのサンプル</title> </head> <body> <p>コメントしてください。</p> <form method="POST" action="index.php"> <input name="comment" /> <input type="submit" value="送信" /> </form> </body> </html>php1
<?php //commentがPOSTされているなら if(isset($_POST["comment"])){ //エスケープしてから表示 $comment = htmlspecialchars($_POST["comment"]); print("あなたのコメントは「 ${comment} 」です。"); } else { ?>最後にこの課題があります。
[課題]送信する内容を変更してみよう
掲示板に必要な情報としては少なくとも名前と本文が必要です。名前も送信し、受け取るように変更してみましょう。余力のある人はタイトル・文字色・メールアドレスなども追加してみましょう。なんかとりえあえず複数のデータを送ってみてほしいとのことだったので、僕は次のようにしました。
index.html2
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>POSTのサンプル</title> </head> <body> <style> .cell{ padding: 1px 15px; margin: 1px 30px; line-height: 0.1; } </style> <h1>「同窓会の参加有無」</h1> <div class=cell> <form method="POST" action="index.php"> <ol> <li><p>氏名:<input name="name" /></p></li> <li><p>メール:<input name="mail" /></p></li> <li><p>参加可否:<input name="comment" /></p></li> <input type="submit" value="送信" style= "width:150px;,height:100px;"/> </div> </form> </body> </html>php 2
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>POSTのサンプル</title> </head> <body> <?php //commentがPOSTされているなら if(isset($_POST["mail"],$_POST["name"],$_POST["comment"])){ //エスケープしてから表示 $mails = htmlspecialchars($_POST["mail"]); $names = htmlspecialchars($_POST["name"]); $comments = htmlspecialchars($_POST["comment"]); print("あなたの入力した情報は以下になります。<br/>"); print("名前:${mails}<br/>"); print("メール:${names}<br/>"); print("参加有無:${comments}<br/>"); }else{ print("情報の入力が正しくありません。"); } ?> </body> </html>震えるくらいクソコードであることはなんとなくですが、自覚してます....
STEP1-9.PHPでデータベースを操作してみる
これやってみたのですが、すごい勉強になりました。
phpでデータベースをこうやっていじるんだ!みたいなのがなんとなくですが理解できます。こちらも特に説明を読んでいけば問題なく進めました。
唯一初心者目線でひっかかりそうなのが、データベースにアクセスするときに自分でつけたデータベースの名前じゃないと、エラーになるので注意が必要。
僕の場合はdbname=「TEST」ではなくて「text」でしたので最初はエラってました。実行結果1
先程はDBのname,textを全て表示したが今度はJohnにしぼったものだけを表示させます。
実行コード
<?php $dsn = 'pgsql:dbname=test;host=pgsql;port=5432'; $user = 'postgres'; $pass = 'example'; try { // DBに接続する $dbh = new PDO($dsn, $user, $pass); //$query_result = $dbh->query('SELECT * FROM test_comments'); $sth_select = $dbh->prepare('SELECT * FROM test_comments WHERE name = ?'); // prepareメソッド(INSERT)最下部でinsertするname/textを定義 $sth = $dbh->prepare('INSERT INTO test_comments (name, text) VALUES (?, ?)'); // DBを切断する $dbh = null; } catch (PDOException $e) { // 接続にエラーが発生した場合ここに入る print "DB ERROR: " . $e->getMessage() . "<br/>"; die(); } ?> <?php //これでdbのnameとtextに新たに文字列が加わる $name = "John"; $text = "Power to the People"; $sth->execute(array($name, $text)); ?> <?php $name = "John"; $sth_select->execute(array($name)); //実行したクエリから実行結果を取得している $prepare_result = $sth_select->fetchAll(); foreach($prepare_result as $row) { print $row["name"] . ": " . $row["text"] . "<br/>"; } $sth_select->execute(array($name)); ?>実行結果2
とりあえず、無事表示されました。
次は気が向いたらSTEP2をやります。
- 投稿日:2019-04-11T23:25:50+09:00
初心者がteamlabのオンラインスキルアップ課題step1をやってみた(コード初心者向け記事)
dockerって何とか、DBとの連携でコード上で具体的にどうするのとか、初心者的にはイメージがつかないほど良くわからないので、teamlabさんのオンラインスキルアップ課題をやってみた。
こちらから課題にアクセスします。
STEP1の内容は下記のようになっています。
- インターネットのしくみ
- WEBサーバについて
- HTMLとCSSについて 4-a. 【Windows】Dockerと開発環境の作り方 4-b. 【Mac】Dockerと開発環境の作り方
- PHPを書いてみる
- PHPでGET/POSTをやってみる
- データベースについて
- SQLを書いてみる
- PHPでデータベースを操作してみる
- 10. GitとGitHubについて
4-b:【Mac】Dockerと開発環境の作り方
1,2,3はわかった気になってとりあえず進めて、まずは4のDockerのセットアップから入ります。
docker-compose -vdockerがちゃんとインストールされているか上記のコマンドで確かめます。
docker-compose up -dteamlabさんのサイトからダウンロードしたフォルダに遷移して、上のコマンドを叩くとコンテナを作成して、起動します。
※Dockerのコマンドに関してはこちら
なんかいろいろエラーは起きたのですが、無事?doneになっています。
「skillup-php-step1-master」をダウンロードして解凍したフォルダに移動したいけど移動できない!っていう場合にですが、フォルダさえ探せれば、フォルダごとターミナルに落としてあげることでpathが表示されるので、あとは先頭にcdつけるだけでフォルダに移動できるはずです。1-6:PHPでGET/POSTをやってみる
1-5は普通にコピペでコード貼って、Dockerで立ち上げたlocalhostにアクセスするだけなので、はしおります。
まず、エディターがない人は適当なエディターをインストールしてください。
(ぼくはsublimeをつかっています。)とりあえず、課題のpostだけやってみました
index.html1
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>POSTのサンプル</title> </head> <body> <p>コメントしてください。</p> <form method="POST" action="index.php"> <input name="comment" /> <input type="submit" value="送信" /> </form> </body> </html>php1
<?php //commentがPOSTされているなら if(isset($_POST["comment"])){ //エスケープしてから表示 $comment = htmlspecialchars($_POST["comment"]); print("あなたのコメントは「 ${comment} 」です。"); } else { ?>最後にこの課題があります。
[課題]送信する内容を変更してみよう
掲示板に必要な情報としては少なくとも名前と本文が必要です。名前も送信し、受け取るように変更してみましょう。余力のある人はタイトル・文字色・メールアドレスなども追加してみましょう。なんかとりえあえず複数のデータを送ってみてほしいとのことだったので、僕は次のようにしました。
index.html2
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>POSTのサンプル</title> </head> <body> <style> .cell{ padding: 1px 15px; margin: 1px 30px; line-height: 0.1; } </style> <h1>「同窓会の参加有無」</h1> <div class=cell> <form method="POST" action="index.php"> <ol> <li><p>氏名:<input name="name" /></p></li> <li><p>メール:<input name="mail" /></p></li> <li><p>参加可否:<input name="comment" /></p></li> <input type="submit" value="送信" style= "width:150px;,height:100px;"/> </div> </form> </body> </html>php 2
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>POSTのサンプル</title> </head> <body> <?php //commentがPOSTされているなら if(isset($_POST["mail"],$_POST["name"],$_POST["comment"])){ //エスケープしてから表示 $mails = htmlspecialchars($_POST["mail"]); $names = htmlspecialchars($_POST["name"]); $comments = htmlspecialchars($_POST["comment"]); print("あなたの入力した情報は以下になります。<br/>"); print("名前:${mails}<br/>"); print("メール:${names}<br/>"); print("参加有無:${comments}<br/>"); }else{ print("情報の入力が正しくありません。"); } ?> </body> </html>震えるくらいクソコードであることはなんとなくですが、自覚してます....
STEP1-9.PHPでデータベースを操作してみる
これやってみたのですが、すごい勉強になりました。
phpでデータベースをこうやっていじるんだ!みたいなのがなんとなくですが理解できます。こちらも特に説明を読んでいけば問題なく進めました。
唯一初心者目線でひっかかりそうなのが、データベースにアクセスするときに自分でつけたデータベースの名前じゃないと、エラーになるので注意が必要。
僕の場合はdbname=「TEST」ではなくて「text」でしたので最初はエラってました。実行結果1
先程はDBのname,textを全て表示したが今度はJohnにしぼったものだけを表示させます。
実行コード
<?php $dsn = 'pgsql:dbname=test;host=pgsql;port=5432'; $user = 'postgres'; $pass = 'example'; try { // DBに接続する $dbh = new PDO($dsn, $user, $pass); //$query_result = $dbh->query('SELECT * FROM test_comments'); $sth_select = $dbh->prepare('SELECT * FROM test_comments WHERE name = ?'); // prepareメソッド(INSERT)最下部でinsertするname/textを定義 $sth = $dbh->prepare('INSERT INTO test_comments (name, text) VALUES (?, ?)'); // DBを切断する $dbh = null; } catch (PDOException $e) { // 接続にエラーが発生した場合ここに入る print "DB ERROR: " . $e->getMessage() . "<br/>"; die(); } ?> <?php //これでdbのnameとtextに新たに文字列が加わる $name = "John"; $text = "Power to the People"; $sth->execute(array($name, $text)); ?> <?php $name = "John"; $sth_select->execute(array($name)); //実行したクエリから実行結果を取得している $prepare_result = $sth_select->fetchAll(); foreach($prepare_result as $row) { print $row["name"] . ": " . $row["text"] . "<br/>"; } $sth_select->execute(array($name)); ?>実行結果2
とりあえず、無事表示されました。
次は気が向いたらSTEP2をやります。
- 投稿日:2019-04-11T19:12:17+09:00
DockerでFailed to fetch debian
突然Dockerが起動しなくなった。
Macのストレージが一杯になったので、Dockerimage系ファイル全部消しました。
(50GBくらい減った。)
いざ再起動しようとすると、、
$ ./docker/bin/compose build
W: Failed to fetch http://deb.debian.org/debian/dists/jessie-updates/main/binary-amd64/Packages 404 Not Found.debian触ってないし、先月まで動いていたし、、
先人の知恵
Dockerfileの
apt-get updateする前にRUN sed -i '/jessie-updates/d' /etc/apt/sources.list入れたらできました!
debianのライブラリの置き場所が変わったみたいです。
(3月後半から起き始めたみたいで、stackoverflowに感謝です)
- 投稿日:2019-04-11T16:56:36+09:00
Prisma
Prisma.ioとは?
- SQLサーバにGraphQLを生やします。
- 今の所、MySQL、PostgreSQL、MongoDBに対応。
- PrismaサーバはDockerコンテナとして起動。
- GraphQLなので、クライアントはHTTPが使えればPrismaサーバを操作できる。
- Prismaサーバの操作をしやすくするPrismaクライアント(GO, TypeScript, JavaScript)を自動生成できる。
- Prisma Adminでブラウザからデータベースの照会、更新などができる。
雑なまとめなので、公式サイトを見てもらったほうがいいと思います。
また、以下の記事がすごく参考になりました。ありがとうございます。
prisma - 最速 GraphQL Server実装 - Qiita
Prisma.ioでGraphQL APIサーバーを楽して作る - Qiita構成
PrismaサーバはSQLサーバのCRUD全てが出来てしまうので、そのまま公開するのは危険。
なので、アプリケーション/APIサーバの層を追加します。この層はPrismaクライアントを使って自前で作るので、APIはGraphQLでなくてもOK。
(REST,gRPCとか)
Database
MySQL。Dockerで構築。prisma initで自動的に作ってくれる。Data Access Layer(Prisma)
Dockerで構築。prisma initで自動的に作ってくれる。Application / API Service
今回はGoで作成。 GraphQLサーバのフレームワークはgqlgenを使用。
最初はホストで直接起動。後からDocker化。Client(ブラウザ)
gqlgenでGraphQL Playgroundを追加できるので、そこから操作。
自分はGraphiQLも使ってます。基本的に公式のチュートリアルに沿って進めますが、所々アレンジ入れてます。
完成後のソースはこちらです。
環境一覧
試した時の環境です。
環境やバージョンが違っても動くとは思います。
- macOS Mojave
- Docker version 18.09.2, build 6247962
- docker-compose version 1.21.2, build a133471
- Node.js v8.15.1 ※prismaインストールのため
公式ではbrewも書いてありますが、途中で以下のエラーに遭遇したので、
npmで入れ直しました。brew tap prisma/prisma brew install prisma Error: Cannot find module 'generate'Step1 Set up Prisma
Prisma インストール
$ npm install -g prisma $ prisma -v prisma/1.30.0 (darwin-x64) node-v8.15.1Prisma init
構築は
GOHOMEのディレクトリ下で構築します。(例: ~/go/src/prisma-hello-world)まず、prismaコマンドで土台を作ります。
途中質問がくるので、以下を選択。
- Create new database
- MySQL
- Go
$ cd ~/go/src $ prisma init prisma-hello-world ? Set up a new Prisma server or deploy to an existing server? Create new database ? What kind of database do you want to deploy to? MySQL ? Select the programming language for the generated Prisma client Prisma Go Client Created 3 new files: prisma.yml Prisma service definition datamodel.prisma GraphQL SDL-based datamodel (foundation for database) docker-compose.yml Docker configuration file Next steps: 1. Open folder: cd prisma-hello-world 2. Start your Prisma server: docker-compose up -d 3. Deploy your Prisma service: prisma deploy 4. Read more about Prisma server: http://bit.ly/prisma-server-overview実行が終わるとファイルがいくつか作成されています。
まず、DBサーバとPrismaサーバを起動するdocker-composeファイル。
docker-compose.ymlversion: '3' services: prisma: image: prismagraphql/prisma:1.30 restart: always ports: - "4466:4466" environment: PRISMA_CONFIG: | port: 4466 # uncomment the next line and provide the env var PRISMA_MANAGEMENT_API_SECRET=my-secret to activate cluster security # managementApiSecret: my-secret databases: default: connector: mysql host: mysql user: root password: prisma rawAccess: true port: 3306 migrations: true mysql: image: mysql:5.7 restart: always environment: MYSQL_ROOT_PASSWORD: prisma volumes: - mysql:/var/lib/mysql volumes: mysql:データモデル定義のパスや、Prismaクライアントの出力先とかの設定ファイル。
prisma.ymlendpoint: http://localhost:4466 datamodel: datamodel.prisma generate: - generator: go-client output: ./generated/prisma-client/データモデル定義。
datamodel.prismatype User { id: ID! @unique name: String! }起動・デプロイ
まずは初期状態で起動してみます。
$ docker-compose up -d $ prisma deploy以下にアクセスすると、PrismaサーバのGraphQL Playgroundが開きます。
以下のアドレスにアクセスすると、データ管理が出来るPrisma Adminが開きます。
Goクライアントを作成
データが空っぽなので、Goクライアントを実装してデータを追加してみます。
まず、GO MODULESを初期化します。
$ export GO111MODLUE=on $ go initPrismaクライアントを使ってデータを登録するソースを作成します。
index.gopackage main import ( "context" "fmt" prisma "prisma-hello-world/generated/prisma-client" ) func main() { client := prisma.New(nil) ctx := context.TODO() // Create a new user name := "Alice" newUser, err := client.CreateUser(prisma.UserCreateInput{ Name: name, }).Exec(ctx) if err != nil { panic(err) } fmt.Printf("Created new user: %+v\n", newUser) users, err := client.Users(nil).Exec(ctx) if err != nil { panic(err) } fmt.Printf("%+v\n", users) }実行すると、1件データが登録されます。
IDはcuidに基づいて自動的に振られます。$ go run index.go Created new user: &{ID:cjuc0tk8f001l07165y3waxtt Name:Alice} [{ID:cjuc0tk8f001l07165y3waxtt Name:Alice}]Step2 データモデルの変更
データモデルに項目を追加します。
datamodel.prismatype User { id: ID! @unique email: String @unique name: String! posts: [Post!]! } type Post { id: ID! @unique title: String! published: Boolean! @default(value: "false") author: User }デプロイとPrismaクライアントの更新をします。
$ prisma deploy $ prisma generate
generated/prisma-client/prisma.goに新しいAPIが追加されましたので、これを使ってデータを登録するソースを作成します。index.gopackage main import ( "context" "fmt" prisma "prisma-hello-world/generated/prisma-client" ) func main() { client := prisma.New(nil) ctx := context.TODO() // Create a new user with two posts name := "Bob" email := "bob@prisma.io" title1 := "Join us for GraphQL Conf in 2019" title2 := "Subscribe to GraphQL Weekly for GraphQL news" newUser, err := client.CreateUser(prisma.UserCreateInput{ Name: name, Email: &email, Posts: &prisma.PostCreateManyWithoutAuthorInput{ Create: []prisma.PostCreateWithoutAuthorInput{ prisma.PostCreateWithoutAuthorInput{ Title: title1, }, prisma.PostCreateWithoutAuthorInput{ Title: title2, }, }, }, }).Exec(ctx) if err != nil { panic(err) } fmt.Printf("Created new user: %+v\n", newUser) allUsers, err := client.Users(nil).Exec(ctx) if err != nil { panic(err) } fmt.Printf("%+v\n", allUsers) allPosts, err := client.Posts(nil).Exec(ctx) if err != nil { panic(err) } fmt.Printf("%+v\n", allPosts) }実行すると、新しいユーザ
Bobと記事が2件追加されます。$ go run index.go Created new user: &{ID:cjuc1dwo1002207164z8feea9 Email:0xc000093520 Name:Bob} [{ID:cjuc0tk8f001l07165y3waxtt Email:<nil> Name:Alice} {ID:cjuc1dwo1002207164z8feea9 Email:0xc000146320 Name:Bob}] [{ID:cjuc1dwp4002307162oty6fva Title:Join us for GraphQL Conf in 2019 Published:false} {ID:cjuc1dwpv00250716kvvo5xab Title:Subscribe to GraphQL Weekly for GraphQL news Published:false}]次に、登録した記事をemailを指定して検索してみます。
index.gopackage main import ( "context" "fmt" prisma "prisma-hello-world/generated/prisma-client" ) func main() { client := prisma.New(nil) ctx := context.TODO() email := "bob@prisma.io" postsByUser, err := client.User(prisma.UserWhereUniqueInput{ Email: &email, }).Posts(nil).Exec(ctx) if err != nil { panic(err) } fmt.Printf("%+v\n", postsByUser) }$ go run index.go [{ID:cjuc1dwp4002307162oty6fva Title:Join us for GraphQL Conf in 2019 Published:false} {ID:cjuc1dwpv00250716kvvo5xab Title:Subscribe to GraphQL Weekly for GraphQL news Published:false}]Step3 Build an App
次に、公開用のGraphQLサーバを作っていきます。
まず、gqlgenのパッケージを登録し、初期構築コマンドを入力します。
$ go get github.com/99designs/gqlgen $ go run github.com/99designs/gqlgen init実行すると以下のファイルが出来ます。
gqlgen.yml
gqlgenの設定。自動生成コードの出力先とかを設定。schema.graphql
公開するGrapQLのスキーマ。この定義からコードが自動生成される。generated.go
gqlgenで自動生成されるコード。
自動生成するので、一旦削除。models_gen.go
prisma-clientで作成された構造体を使うので不要。削除。resolver.go
GraphQLのリゾルバ。自分で作る必要があるが、必要な関数などのテンプレートは自動生成してくれる。
自動生成するので、一旦削除。server/server.go
GraphQLサーバ起動のコードごちゃごちゃして来たので、フォルダを作って整理します。
- gqlgen/
- gqlgen.yml
- schema.graphql
- server/server.go
次に、
gqlgenの設定をPrismaに合わせて書き換えます。gqlgen.ymlschema: schema.graphql exec: filename: generated.go models: Post: model: prisma-hello-world/generated/prisma-client.Post User: model: prisma-hello-world/generated/prisma-client.User resolver: filename: resolver.go type: Resolver公開するGraphQLのスキーマを作成します。
schema.graphqltype Query { publishedPosts: [Post!]! post(postId: ID!): Post postsByUser(userId: ID!): [Post!]! } type Mutation { createUser(name: String!): User createDraft(title: String!, userId: ID!): Post publish(postId: ID!): Post } type User { id: ID! email: String name: String! posts: [Post!]! } type Post { id: ID! title: String! published: Boolean! author: User }ファイルが出来たら、
gqlgenを実行してソースを自動生成します。$ cd gqlgen $ go run github.com/99designs/gqlgen以下のファイルが出来ました。
- gqlgen/
- generated.go
- resolver.go
自動生成されたGraphQLのリゾルバは枠しかないので、Prismaクライアントを使って実装していきます。
gqlgen/resolver.go//go:generate go run github.com/99designs/gqlgen package gqlgen import ( "context" "prisma-hello-world/generated/prisma-client" ) type Resolver struct { Prisma *prisma.Client } func (r *Resolver) Mutation() MutationResolver { return &mutationResolver{r} } func (r *Resolver) Post() PostResolver { return &postResolver{r} } func (r *Resolver) Query() QueryResolver { return &queryResolver{r} } func (r *Resolver) User() UserResolver { return &userResolver{r} } type mutationResolver struct{ *Resolver } func (r *mutationResolver) CreateUser(ctx context.Context, name string) (*prisma.User, error) { return r.Prisma.CreateUser(prisma.UserCreateInput{ Name: name, }).Exec(ctx) } func (r *mutationResolver) CreateDraft(ctx context.Context, title string, userId string) (*prisma.Post, error) { return r.Prisma.CreatePost(prisma.PostCreateInput{ Title: title, Author: &prisma.UserCreateOneWithoutPostsInput{ Connect: &prisma.UserWhereUniqueInput{ID: &userId}, }, }).Exec(ctx) } func (r *mutationResolver) Publish(ctx context.Context, postId string) (*prisma.Post, error) { published := true return r.Prisma.UpdatePost(prisma.PostUpdateParams{ Where: prisma.PostWhereUniqueInput{ID: &postId}, Data: prisma.PostUpdateInput{Published: &published}, }).Exec(ctx) } type postResolver struct{ *Resolver } func (r *postResolver) Author(ctx context.Context, obj *prisma.Post) (*prisma.User, error) { return r.Prisma.Post(prisma.PostWhereUniqueInput{ID: &obj.ID}).Author().Exec(ctx) } type queryResolver struct{ *Resolver } func (r *queryResolver) PublishedPosts(ctx context.Context) ([]prisma.Post, error) { published := true return r.Prisma.Posts(&prisma.PostsParams{ Where: &prisma.PostWhereInput{Published: &published}, }).Exec(ctx) } func (r *queryResolver) Post(ctx context.Context, postId string) (*prisma.Post, error) { return r.Prisma.Post(prisma.PostWhereUniqueInput{ID: &postId}).Exec(ctx) } func (r *queryResolver) PostsByUser(ctx context.Context, userId string) ([]prisma.Post, error) { return r.Prisma.Posts(&prisma.PostsParams{ Where: &prisma.PostWhereInput{ Author: &prisma.UserWhereInput{ ID: &userId, }}, }).Exec(ctx) } type userResolver struct{ *Resolver } func (r *userResolver) Posts(ctx context.Context, obj *prisma.User) ([]prisma.Post, error) { return r.Prisma.User(prisma.UserWhereUniqueInput{ID: &obj.ID}).Posts(nil).Exec(ctx) }先頭の
//go:generate go run github.com/99designs/gqlgenは、go generateコマンドでgqlgenを実行するためのコメントです。
スキーマを修正したら、以下のコマンドでコードを更新できます。例$ go generate gqlgen/resolver.go次に、アプリ起動部分を作成します。
server/server.gopackage main import ( "log" "net/http" "os" prisma "prisma-hello-world/generated/prisma-client" "prisma-hello-world/gqlgen" "github.com/99designs/gqlgen/handler" ) const defaultPort = "4000" func main() { port := os.Getenv("PORT") if len(port) == 0 { port = defaultPort } client := prisma.New(nil) resolver := gqlgen.Resolver{ Prisma: client, } http.Handle("/", handler.Playground("GraphQL Playground", "/query")) http.Handle("/query", handler.GraphQL(gqlgen.NewExecutableSchema( gqlgen.Config{Resolvers: &resolver}))) log.Printf("Server is running on http://localhost:%s", port) err := http.ListenAndServe(":"+port, nil) if err != nil { log.Fatal(err) } }できたら、起動してみます。
$ go run server/server.go以下にアクセスすると、GraphQL Playgroundが開きます。
ためしに、ユーザや記事を追加してみます。
query-ユーザ追加mutation { createUser(name: "otanu") { id name } }結果{ "data": { "createUser": { "id": "cjuc3vysh000d0744f8n94vw4", "name": "otanu" } } }query-記事追加mutation { createDraft(title: "テスト", userId: "cjuc3vysh000d0744f8n94vw4") { id title published author { id name } } }結果{ "data": { "createDraft": { "id": "cjuc42km0000j07441ucjddnd", "title": "テスト", "published": false, "author": { "id": "cjuc3vysh000d0744f8n94vw4", "name": "otanu" } } } }query-公開mutation { publish(postId: "cjuc42km0000j07441ucjddnd") { id title published author { name } } }結果{ "data": { "publish": { "id": "cjuc42km0000j07441ucjddnd", "title": "テスト", "published": true, "author": { "name": "otanu" } } } }query-公開記事検索query { publishedPosts { id title } }結果{ "data": { "publishedPosts": [ { "id": "cjuc42km0000j07441ucjddnd", "title": "テスト" } ] } }アプリのDocker化
アプリもDockerComposeでまとめて起動できるように、Docker化していきます。
アプリをDocker化すると、prismaサーバへの接続がlocalhostでは繋がらななくなるので、環境変数
ENDPOINTを追加して、エンドポイントを変更できるようにします。server/server.gopackage main import ( "log" "net/http" "os" prisma "prisma-hello-world/generated/prisma-client" "prisma-hello-world/gqlgen" "github.com/99designs/gqlgen/handler" ) const defaultPort = "4000" func main() { port := os.Getenv("PORT") if len(port) == 0 { port = defaultPort } // 追加 var opt *prisma.Options endpoint := os.Getenv("ENDPOINT") if len(endpoint) != 0 { opt = &prisma.Options{ Endpoint: endpoint, } } client := prisma.New(opt) resolver := gqlgen.Resolver{ Prisma: client, } http.Handle("/", handler.Playground("GraphQL Playground", "/query")) http.Handle("/query", handler.GraphQL(gqlgen.NewExecutableSchema( gqlgen.Config{Resolvers: &resolver}))) log.Printf("Server is running on http://localhost:%s", port) err := http.ListenAndServe(":"+port, nil) if err != nil { log.Fatal(err) } }次にDockerfileを準備します。
ついでにfreshでホットリロードも追加。DockerfileFROM golang:1.11-alpine AS build_base RUN apk add bash ca-certificates git gcc g++ libc-dev WORKDIR /app COPY go.mod . COPY go.sum . RUN go mod download RUN go get github.com/pilu/fresh COPY . . EXPOSE 4000 CMD cd server; fresh server.goDockerComposeにアプリの設定を追加。
これで、まとめて起動できるようになりました。docker-compose.ymlversion: '3' services: prisma: image: prismagraphql/prisma:1.30 restart: always ports: - "4466:4466" environment: PRISMA_CONFIG: | port: 4466 # uncomment the next line and provide the env var PRISMA_MANAGEMENT_API_SECRET=my-secret to activate cluster security # managementApiSecret: my-secret databases: default: connector: mysql host: mysql user: root password: prisma rawAccess: true port: 3306 migrations: true mysql: image: mysql:5.7 restart: always ports: - "3306:3306" environment: MYSQL_ROOT_PASSWORD: prisma volumes: - mysql:/var/lib/mysql app: build: context: . dockerfile: ./Dockerfile ports: - "4000:4000" volumes: - .:/app depends_on: - prisma environment: ENDPOINT: http://prisma:4466 volumes: mysql:
- 投稿日:2019-04-11T16:56:36+09:00
Prisma.io + Go のチュートリアル
Prisma.ioとは?
- SQLサーバにGraphQLを生やします。
- 今の所、MySQL、PostgreSQL、MongoDBに対応。
- PrismaサーバはDockerコンテナとして起動。
- GraphQLなので、クライアントはHTTPが使えればPrismaサーバを操作できる。
- Prismaサーバの操作をしやすくするPrismaクライアント(GO, TypeScript, JavaScript)を自動生成できる。
- Prisma Adminでブラウザからデータベースの照会、更新などができる。
雑なまとめなので、公式サイトを見てもらったほうがいいと思います。
また、以下の記事がすごく参考になりました。ありがとうございます。
prisma - 最速 GraphQL Server実装 - Qiita
Prisma.ioでGraphQL APIサーバーを楽して作る - Qiita構成
PrismaサーバはSQLサーバのCRUD全てが出来てしまうので、そのまま公開するのは危険。
なので、アプリケーション/APIサーバの層を追加します。この層はPrismaクライアントを使って自前で作るので、APIはGraphQLでなくてもOK。
(REST,gRPCとか)
Database
MySQL。Dockerで構築。prisma initで自動的に作ってくれる。Data Access Layer(Prisma)
Dockerで構築。prisma initで自動的に作ってくれる。Application / API Service
今回はGoで作成。 GraphQLサーバのフレームワークはgqlgenを使用。
最初はホストで直接起動。後からDocker化。Client(ブラウザ)
gqlgenでGraphQL Playgroundを追加できるので、そこから操作。
自分はGraphiQLも使ってます。基本的に公式のチュートリアルに沿って進めますが、所々アレンジ入れてます。
完成後のソースはこちらです。
環境一覧
試した時の環境です。
環境やバージョンが違っても動くとは思います。
- macOS Mojave
- Docker version 18.09.2, build 6247962
- docker-compose version 1.21.2, build a133471
- Node.js v8.15.1 ※prismaインストールのため
公式ではbrewも書いてありますが、途中で以下のエラーに遭遇したので、
npmで入れ直しました。brew tap prisma/prisma brew install prisma Error: Cannot find module 'generate'Step1 Set up Prisma
Prisma インストール
$ npm install -g prisma $ prisma -v prisma/1.30.0 (darwin-x64) node-v8.15.1Prisma init
構築は
GOHOMEのディレクトリ下で構築します。(例: ~/go/src/prisma-hello-world)まず、prismaコマンドで土台を作ります。
途中質問がくるので、以下を選択。
- Create new database
- MySQL
- Go
$ cd ~/go/src $ prisma init prisma-hello-world ? Set up a new Prisma server or deploy to an existing server? Create new database ? What kind of database do you want to deploy to? MySQL ? Select the programming language for the generated Prisma client Prisma Go Client Created 3 new files: prisma.yml Prisma service definition datamodel.prisma GraphQL SDL-based datamodel (foundation for database) docker-compose.yml Docker configuration file Next steps: 1. Open folder: cd prisma-hello-world 2. Start your Prisma server: docker-compose up -d 3. Deploy your Prisma service: prisma deploy 4. Read more about Prisma server: http://bit.ly/prisma-server-overview実行が終わるとファイルがいくつか作成されています。
まず、DBサーバとPrismaサーバを起動するdocker-composeファイル。
docker-compose.ymlversion: '3' services: prisma: image: prismagraphql/prisma:1.30 restart: always ports: - "4466:4466" environment: PRISMA_CONFIG: | port: 4466 # uncomment the next line and provide the env var PRISMA_MANAGEMENT_API_SECRET=my-secret to activate cluster security # managementApiSecret: my-secret databases: default: connector: mysql host: mysql user: root password: prisma rawAccess: true port: 3306 migrations: true mysql: image: mysql:5.7 restart: always environment: MYSQL_ROOT_PASSWORD: prisma volumes: - mysql:/var/lib/mysql volumes: mysql:データモデル定義のパスや、Prismaクライアントの出力先とかの設定ファイル。
prisma.ymlendpoint: http://localhost:4466 datamodel: datamodel.prisma generate: - generator: go-client output: ./generated/prisma-client/データモデル定義。
datamodel.prismatype User { id: ID! @unique name: String! }起動・デプロイ
まずは初期状態で起動してみます。
$ docker-compose up -d $ prisma deploy以下にアクセスすると、PrismaサーバのGraphQL Playgroundが開きます。
以下のアドレスにアクセスすると、データ管理が出来るPrisma Adminが開きます。
Goクライアントを作成
データが空っぽなので、Goクライアントを実装してデータを追加してみます。
まず、GO MODULESを初期化します。
$ export GO111MODLUE=on $ go initPrismaクライアントを使ってデータを登録するソースを作成します。
index.gopackage main import ( "context" "fmt" prisma "prisma-hello-world/generated/prisma-client" ) func main() { client := prisma.New(nil) ctx := context.TODO() // Create a new user name := "Alice" newUser, err := client.CreateUser(prisma.UserCreateInput{ Name: name, }).Exec(ctx) if err != nil { panic(err) } fmt.Printf("Created new user: %+v\n", newUser) users, err := client.Users(nil).Exec(ctx) if err != nil { panic(err) } fmt.Printf("%+v\n", users) }実行すると、1件データが登録されます。
IDはcuidに基づいて自動的に振られます。$ go run index.go Created new user: &{ID:cjuc0tk8f001l07165y3waxtt Name:Alice} [{ID:cjuc0tk8f001l07165y3waxtt Name:Alice}]Step2 データモデルの変更
データモデルに項目を追加します。
datamodel.prismatype User { id: ID! @unique email: String @unique name: String! posts: [Post!]! } type Post { id: ID! @unique title: String! published: Boolean! @default(value: "false") author: User }デプロイとPrismaクライアントの更新をします。
$ prisma deploy $ prisma generate
generated/prisma-client/prisma.goに新しいAPIが追加されましたので、これを使ってデータを登録するソースを作成します。index.gopackage main import ( "context" "fmt" prisma "prisma-hello-world/generated/prisma-client" ) func main() { client := prisma.New(nil) ctx := context.TODO() // Create a new user with two posts name := "Bob" email := "bob@prisma.io" title1 := "Join us for GraphQL Conf in 2019" title2 := "Subscribe to GraphQL Weekly for GraphQL news" newUser, err := client.CreateUser(prisma.UserCreateInput{ Name: name, Email: &email, Posts: &prisma.PostCreateManyWithoutAuthorInput{ Create: []prisma.PostCreateWithoutAuthorInput{ prisma.PostCreateWithoutAuthorInput{ Title: title1, }, prisma.PostCreateWithoutAuthorInput{ Title: title2, }, }, }, }).Exec(ctx) if err != nil { panic(err) } fmt.Printf("Created new user: %+v\n", newUser) allUsers, err := client.Users(nil).Exec(ctx) if err != nil { panic(err) } fmt.Printf("%+v\n", allUsers) allPosts, err := client.Posts(nil).Exec(ctx) if err != nil { panic(err) } fmt.Printf("%+v\n", allPosts) }実行すると、新しいユーザ
Bobと記事が2件追加されます。$ go run index.go Created new user: &{ID:cjuc1dwo1002207164z8feea9 Email:0xc000093520 Name:Bob} [{ID:cjuc0tk8f001l07165y3waxtt Email:<nil> Name:Alice} {ID:cjuc1dwo1002207164z8feea9 Email:0xc000146320 Name:Bob}] [{ID:cjuc1dwp4002307162oty6fva Title:Join us for GraphQL Conf in 2019 Published:false} {ID:cjuc1dwpv00250716kvvo5xab Title:Subscribe to GraphQL Weekly for GraphQL news Published:false}]次に、登録した記事をemailを指定して検索してみます。
index.gopackage main import ( "context" "fmt" prisma "prisma-hello-world/generated/prisma-client" ) func main() { client := prisma.New(nil) ctx := context.TODO() email := "bob@prisma.io" postsByUser, err := client.User(prisma.UserWhereUniqueInput{ Email: &email, }).Posts(nil).Exec(ctx) if err != nil { panic(err) } fmt.Printf("%+v\n", postsByUser) }$ go run index.go [{ID:cjuc1dwp4002307162oty6fva Title:Join us for GraphQL Conf in 2019 Published:false} {ID:cjuc1dwpv00250716kvvo5xab Title:Subscribe to GraphQL Weekly for GraphQL news Published:false}]Step3 Build an App
次に、公開用のGraphQLサーバを作っていきます。
まず、gqlgenのパッケージを登録し、初期構築コマンドを入力します。
$ go get github.com/99designs/gqlgen $ go run github.com/99designs/gqlgen init実行すると以下のファイルが出来ます。
gqlgen.yml
gqlgenの設定。自動生成コードの出力先とかを設定。schema.graphql
公開するGrapQLのスキーマ。この定義からコードが自動生成される。generated.go
gqlgenで自動生成されるコード。
自動生成するので、一旦削除。models_gen.go
prisma-clientで作成された構造体を使うので不要。削除。resolver.go
GraphQLのリゾルバ。自分で作る必要があるが、必要な関数などのテンプレートは自動生成してくれる。
自動生成するので、一旦削除。server/server.go
GraphQLサーバ起動のコードごちゃごちゃして来たので、フォルダを作って整理します。
- gqlgen/
- gqlgen.yml
- schema.graphql
- server/server.go
次に、
gqlgenの設定をPrismaに合わせて書き換えます。gqlgen.ymlschema: schema.graphql exec: filename: generated.go models: Post: model: prisma-hello-world/generated/prisma-client.Post User: model: prisma-hello-world/generated/prisma-client.User resolver: filename: resolver.go type: Resolver公開するGraphQLのスキーマを作成します。
schema.graphqltype Query { publishedPosts: [Post!]! post(postId: ID!): Post postsByUser(userId: ID!): [Post!]! } type Mutation { createUser(name: String!): User createDraft(title: String!, userId: ID!): Post publish(postId: ID!): Post } type User { id: ID! email: String name: String! posts: [Post!]! } type Post { id: ID! title: String! published: Boolean! author: User }ファイルが出来たら、
gqlgenを実行してソースを自動生成します。$ cd gqlgen $ go run github.com/99designs/gqlgen以下のファイルが出来ました。
- gqlgen/
- generated.go
- resolver.go
自動生成されたGraphQLのリゾルバは枠しかないので、Prismaクライアントを使って実装していきます。
gqlgen/resolver.go//go:generate go run github.com/99designs/gqlgen package gqlgen import ( "context" "prisma-hello-world/generated/prisma-client" ) type Resolver struct { Prisma *prisma.Client } func (r *Resolver) Mutation() MutationResolver { return &mutationResolver{r} } func (r *Resolver) Post() PostResolver { return &postResolver{r} } func (r *Resolver) Query() QueryResolver { return &queryResolver{r} } func (r *Resolver) User() UserResolver { return &userResolver{r} } type mutationResolver struct{ *Resolver } func (r *mutationResolver) CreateUser(ctx context.Context, name string) (*prisma.User, error) { return r.Prisma.CreateUser(prisma.UserCreateInput{ Name: name, }).Exec(ctx) } func (r *mutationResolver) CreateDraft(ctx context.Context, title string, userId string) (*prisma.Post, error) { return r.Prisma.CreatePost(prisma.PostCreateInput{ Title: title, Author: &prisma.UserCreateOneWithoutPostsInput{ Connect: &prisma.UserWhereUniqueInput{ID: &userId}, }, }).Exec(ctx) } func (r *mutationResolver) Publish(ctx context.Context, postId string) (*prisma.Post, error) { published := true return r.Prisma.UpdatePost(prisma.PostUpdateParams{ Where: prisma.PostWhereUniqueInput{ID: &postId}, Data: prisma.PostUpdateInput{Published: &published}, }).Exec(ctx) } type postResolver struct{ *Resolver } func (r *postResolver) Author(ctx context.Context, obj *prisma.Post) (*prisma.User, error) { return r.Prisma.Post(prisma.PostWhereUniqueInput{ID: &obj.ID}).Author().Exec(ctx) } type queryResolver struct{ *Resolver } func (r *queryResolver) PublishedPosts(ctx context.Context) ([]prisma.Post, error) { published := true return r.Prisma.Posts(&prisma.PostsParams{ Where: &prisma.PostWhereInput{Published: &published}, }).Exec(ctx) } func (r *queryResolver) Post(ctx context.Context, postId string) (*prisma.Post, error) { return r.Prisma.Post(prisma.PostWhereUniqueInput{ID: &postId}).Exec(ctx) } func (r *queryResolver) PostsByUser(ctx context.Context, userId string) ([]prisma.Post, error) { return r.Prisma.Posts(&prisma.PostsParams{ Where: &prisma.PostWhereInput{ Author: &prisma.UserWhereInput{ ID: &userId, }}, }).Exec(ctx) } type userResolver struct{ *Resolver } func (r *userResolver) Posts(ctx context.Context, obj *prisma.User) ([]prisma.Post, error) { return r.Prisma.User(prisma.UserWhereUniqueInput{ID: &obj.ID}).Posts(nil).Exec(ctx) }先頭の
//go:generate go run github.com/99designs/gqlgenは、go generateコマンドでgqlgenを実行するためのコメントです。
スキーマを修正したら、以下のコマンドでコードを更新できます。例$ go generate gqlgen/resolver.go次に、アプリ起動部分を作成します。
server/server.gopackage main import ( "log" "net/http" "os" prisma "prisma-hello-world/generated/prisma-client" "prisma-hello-world/gqlgen" "github.com/99designs/gqlgen/handler" ) const defaultPort = "4000" func main() { port := os.Getenv("PORT") if len(port) == 0 { port = defaultPort } client := prisma.New(nil) resolver := gqlgen.Resolver{ Prisma: client, } http.Handle("/", handler.Playground("GraphQL Playground", "/query")) http.Handle("/query", handler.GraphQL(gqlgen.NewExecutableSchema( gqlgen.Config{Resolvers: &resolver}))) log.Printf("Server is running on http://localhost:%s", port) err := http.ListenAndServe(":"+port, nil) if err != nil { log.Fatal(err) } }できたら、起動してみます。
$ go run server/server.go以下にアクセスすると、GraphQL Playgroundが開きます。
ためしに、ユーザや記事を追加してみます。
query-ユーザ追加mutation { createUser(name: "otanu") { id name } }結果{ "data": { "createUser": { "id": "cjuc3vysh000d0744f8n94vw4", "name": "otanu" } } }query-記事追加mutation { createDraft(title: "テスト", userId: "cjuc3vysh000d0744f8n94vw4") { id title published author { id name } } }結果{ "data": { "createDraft": { "id": "cjuc42km0000j07441ucjddnd", "title": "テスト", "published": false, "author": { "id": "cjuc3vysh000d0744f8n94vw4", "name": "otanu" } } } }query-公開mutation { publish(postId: "cjuc42km0000j07441ucjddnd") { id title published author { name } } }結果{ "data": { "publish": { "id": "cjuc42km0000j07441ucjddnd", "title": "テスト", "published": true, "author": { "name": "otanu" } } } }query-公開記事検索query { publishedPosts { id title } }結果{ "data": { "publishedPosts": [ { "id": "cjuc42km0000j07441ucjddnd", "title": "テスト" } ] } }アプリのDocker化
アプリもDockerComposeでまとめて起動できるように、Docker化していきます。
アプリをDocker化すると、prismaサーバへの接続がlocalhostでは繋がらななくなるので、環境変数
ENDPOINTを追加して、エンドポイントを変更できるようにします。server/server.gopackage main import ( "log" "net/http" "os" prisma "prisma-hello-world/generated/prisma-client" "prisma-hello-world/gqlgen" "github.com/99designs/gqlgen/handler" ) const defaultPort = "4000" func main() { port := os.Getenv("PORT") if len(port) == 0 { port = defaultPort } // 追加 var opt *prisma.Options endpoint := os.Getenv("ENDPOINT") if len(endpoint) != 0 { opt = &prisma.Options{ Endpoint: endpoint, } } client := prisma.New(opt) resolver := gqlgen.Resolver{ Prisma: client, } http.Handle("/", handler.Playground("GraphQL Playground", "/query")) http.Handle("/query", handler.GraphQL(gqlgen.NewExecutableSchema( gqlgen.Config{Resolvers: &resolver}))) log.Printf("Server is running on http://localhost:%s", port) err := http.ListenAndServe(":"+port, nil) if err != nil { log.Fatal(err) } }次にDockerfileを準備します。
ついでにfreshでホットリロードも追加。DockerfileFROM golang:1.11-alpine AS build_base RUN apk add bash ca-certificates git gcc g++ libc-dev WORKDIR /app COPY go.mod . COPY go.sum . RUN go mod download RUN go get github.com/pilu/fresh COPY . . EXPOSE 4000 CMD cd server; fresh server.goDockerComposeにアプリの設定を追加。
これで、まとめて起動できるようになりました。docker-compose.ymlversion: '3' services: prisma: image: prismagraphql/prisma:1.30 restart: always ports: - "4466:4466" environment: PRISMA_CONFIG: | port: 4466 # uncomment the next line and provide the env var PRISMA_MANAGEMENT_API_SECRET=my-secret to activate cluster security # managementApiSecret: my-secret databases: default: connector: mysql host: mysql user: root password: prisma rawAccess: true port: 3306 migrations: true mysql: image: mysql:5.7 restart: always ports: - "3306:3306" environment: MYSQL_ROOT_PASSWORD: prisma volumes: - mysql:/var/lib/mysql app: build: context: . dockerfile: ./Dockerfile ports: - "4000:4000" volumes: - .:/app depends_on: - prisma environment: ENDPOINT: http://prisma:4466 volumes: mysql:
- 投稿日:2019-04-11T14:37:30+09:00
.NET Coreコンソールアプリのコンテナ化について手法図示
はじめに
.Net coreのコンソールアプリをコンテナ化しようといろいろ調べたんですが
自分的にイメージしにくかったので図示してみます。
図
①ベースイメージ取得
Docker Hubからベースとなるイメージを取得してくる。
SDKやらRuntimeやらいろいろある。例えばsdk2.1docker pull mcr.microsoft.com/dotnet/core/sdk:2.1②コンテナを起動して中に入る
GitHubからソースコードを取得する想定docker run -itd --name tmp mcr.microsoft.com/dotnet/core/sdk:2.1 /bin/bash docker exec -it tmp /bin/bash共有フォルダからソースコードを取得しようと思ったら--mountで設定必要
③.net coreソースコード取得
例えば.NetCoreのサンプルアプリのソースコードを取得mkdir -p /src; cd $_ git clone https://github.com/dotnet/core.git cd core/samples/helloworld④dotnet publishでdll作成
mkdir /helloworld dotnet publish -c Release -o /helloworlddotnet /helloworld/helloworld.dllで実行可能な状況になる。
配置には
- フレームワークに依存する展開(Framework-dependent deployment、FDD)
- 自己完結型の展開(Self-contained deployment、SFD)
があるらしい。
コンソールアプリを外部から呼びやすくする方法として.NET Core CLI を使用して .NET Core グローバル ツールを作成するとかも。⑤ docker commitでimage化
コンテナから抜け出てから
docker commit tmp helloworldとするとmcr.microsoft.com/dotnet/core/sdk:2.1をベースとしたhelloworld.dllが実行可能なhelloworldというイメージが新たに出来上がる。
tmpは②で指定したコンテナ名。helloworldはイメージ名。DockerFile
こんなことを毎回手動ではやってられないのでDockerFileで自動化する。
解説はいきなりDockerFileの記述から始まるので根本的なところがわからなかった。dockerfileFROM mcr.microsoft.com/dotnet/core/sdk:2.1 WORKDIR /src RUN git clone https://github.com/dotnet/core.git WORKDIR core/samples/helloworld RUN mkdir /helloworld RUN dotnet publish -c Release -o /helloworld ENTRYPOINT ["dotnet", "/helloworld/helloworld.dll"]上記ファイルがある場所で
docker build -t helloworld .を実行すればイメージが出来上がる。
docker run helloworldで
Hello World!
が出力される。イメージの配置
- 実行環境でdocker build
- 出来上がったイメージを実行環境にエクスポート
とかすれば使えるようになるはず。
参考
- 投稿日:2019-04-11T14:29:11+09:00
AWS ECRにdockerイメージを登録
ECRとは
Amazon Elastic Container Registry (ECR) は、完全マネージド型の Docker コンテナレジストリです。このレジストリを使うと、開発者は Docker コンテナイメージを簡単に保存、管理、デプロイできます。
ECRにレポジトリを作成
以下のコマンドでECRにレポジトリを作成します。
$ aws ecr create-repository --repository-name sample-aws-batch-repoECRにログイン
以下のコマンドを実行すると、ECRにログインします。
$ aws ecr get-login --no-include-email --region ap-northeast-1 --profile ExampleProfile作成したdocker imageに、以下のようにしてtagを付けます。
$ docker tag sample-aws-batch:latest xxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/sample-aws-batch-repo:latestECRにpushします。
$ docker push xxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/sample-aws-batch-repo:latest参考:AWSのECR
- 投稿日:2019-04-11T14:13:56+09:00
docker-compose から docker network を少しだけ理解したい
docker-compose での疑問
docker公式っぽいやつの docker-compose の例 : https://docs.docker.com/compose/gettingstarted/
ここでの
app.pyのredisのhostが以下のように指定されています。cache = redis.Redis(host='redis', port=6379)なぜ
host='redis'で別のコンテナのredisにつなぐことが出来るんだい?上記の公式サイトには以下のように解説されています。
In this example, redis is the hostname of the redis container on the application’s network. We use the default port for Redis, 6379.
はぇ〜
application’s network ってなに
ここでいう
application’s networkとはdocker containerにおけるネットワークのことっぽい?
docker-compose up等で起動されたコンテナ群は、すべて同一のネットワークに所属することになるようです。参考にさせていただいた記事 : https://qiita.com/roba4coding/items/efd3a38db08eb476d412
つまりどういうことだってばよ
docker inspectコマンドを使うことでふわっと概要がわかります。
inspectするためにまず コンテナのIDを調べます。$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES aa690f2ae5d4 example_docker_compose_web "python app-server/s…" 2 minutes ago Up 2 minutes 0.0.0.0:5000->5000/tcp example_docker_compose_web_1 4f39c7c9cc47 redis:alpine "docker-entrypoint.s…" 2 minutes ago Up 2 minutes 6379/tcp example_docker_compose_redis_1
inspectします。$ docker inspect 4f39c7c9cc47 ... "Networks": { "example_docker_compose_default": { "IPAMConfig": null, "Links": null, "Aliases": [ "4f39c7c9cc47", "redis" ], ... } } ...コンテナのID :
4f39c7c9cc47(example_docker_compose_redis_1) がredisというエイリアスで登録されているのですね。このエイリアスを使うことが出来るのが、同一
docker networkに所属するものだけだということですね。上記でいうと コンテナ
aa690f2ae5d4(example_docker_compose_web_1) が エイリアスを使うことが出来るということですね。どこで
redisというエイリアスの名前が決まったかということですが、docker-compose.ymlに書いてあるservicesの直下の定義の名のことみたいですね。version: '3' services: # ↓これ web: build: . ports: - "5000:5000" # ↓これ redis: image: "redis:alpine"docker network ってなに
docker network lsで現在存在するdocker networkの一覧を見ることができます。$ docker network ls NETWORK ID NAME DRIVER SCOPE ac27f0096628 bridge bridge local e72136cdac25 example_docker_compose_default bridge local d2b0552308a8 host host localここで 最初の
docker-composeのexampleで作られたであろうexample_docker_compose_defaultのdocker networkの詳細を見てみましょう。コマンドは
docker network inspectです。$ docker network inspect example_docker_compose_default [ { "Name": "example_docker_compose_default", "Id": "e72136cdac25de9dbc9875467aacd59e916ba8b7122cbede91f81387a2a18715", ... "Containers": { "4f39c7c9cc478dc30aca3bd21c6dc1eda2bb189c0b5264a325f98b38ad8cd7c6": { "Name": "example_docker_compose_redis_1", ... }, "aa690f2ae5d483c0c2cf213d9929a3d49025859464abe095f861c05bbb66ee32": { "Name": "example_docker_compose_web_1", ... } }, ... ]
Containersに 先ほどdocker-composeで作られたコンテナ達がありますね。コンテナIDも一致しているようです。参考にさせていただいた記事 : https://qiita.com/TsutomuNakamura/items/ed046ee21caca4a2ffd9
docker-compose を使わずにやってみよう
今回は別の例として
mysqlが起動しているコンテナ に対してpythonが起動したコンテナからアクセスしたいと思います。docker networkを知らなかった時
まず
mysqlのコンテナをたてます。$ docker run -e MYSQL_ROOT_PASSWORD=root -d -p 3307:3306 --name test-mysql mysql:5.6 4f7475ea1ac4db5d4aad630cbe585faf2dca39db61d7e405e14e9554414bd486
pythonが起動しているコンテナからmysqlのコンテナにアクセスするためには、そのコンテナのアドレスを知る必要があります。$ docker exec test-mysql cat /etc/hosts 127.0.0.1 localhost .. 172.17.0.2 4f7475ea1ac4こうすることでようやく接続することができました。(もっといいやり方あったら教えてください..)
>>> import mysql.connector >>> conn = mysql.connector.connect(host="172.17.0.2",user="root",password="root",port=3306,database="mysql") >>> conn.is_connected() Truedocker networkを使った場合
まず、コンテナが所属するための
docker networkを作ります。
docker networkに関して参考にさせていただいたブログ : https://www.sambaiz.net/article/7/$ docker network create -d bridge test-network 25d355cf117def0e6ce801341e1b535320cd688435a436ce063dc49bbb3c9c0e $ docker network ls NETWORK ID NAME DRIVER SCOPE ac27f0096628 bridge bridge local e72136cdac25 example_docker_compose_default bridge local d2b0552308a8 host host local 07263a6d0de1 test-network bridge localコンテナが作成される時に、作ったネットワークに所属してもらうようにするには、
--netオプションを使うようです。$ docker run -e MYSQL_ROOT_PASSWORD=root -d -p 3307:3306 --name test-mysql --net=test-network --net-alias mysql mysql:5.6 0f901dbda634c3d05cce10d2bf91fb0ef82d39fbd1b1046f284db522bc8387f8こうすることで、
docker-composeで起動したコンテナと同様にエイリアスが登録されます。$ docker inspect 0f901dbda634 ... "Networks": { "test-network": { ... "Aliases": [ "mysql", "0f901dbda634" ] ... } ...そして python が起動するコンテナも同一
docker network上にたててあげれば、$ docker run -it --net=test-network test-python >>> import mysql.connector >>> conn = mysql.connector.connect(host='mysql',user='root',password='root',port=3306,database='mysql') >>> conn.is_connected() True無事、コンテナを名前解決できるようになり、
host='mysql'で接続できているのがわかると思います。
--linkの場合$ docker run -e MYSQL_ROOT_PASSWORD=root -d -p 3307:3306 --name test-mysql --net=test-network mysql:5.6 2d96784fb9ae77cec276558d3439e3b455782bb4bac4291b76b65a27d5c27480 $ docker run -it --net=test-network --link test-mysql:mysql test-python Python 3.7.3 (default, Mar 27 2019, 23:48:15) [GCC 8.2.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> import mysql.connector >>> conn = mysql.connector.connect(host='mysql',user='root',password='root',port=3306,database='mysql') >>> conn.is_connected() True同様に繋ぐことが出来ました。
linkの場合AliasesではなくLinksに名前解決するための情報が書かれていました。... "Networks": { "test-network": { ... "Links": [ "test-mysql:mysql" ], "Aliases": [ "d0d2ed057334" ], ... } } ...
--net-aliasと--linkの使い分けに関してはまだ知識が浅いのでいつか調べたいと思います。まとめ
docker-compose を使おう!
- 投稿日:2019-04-11T11:02:53+09:00
Nuxt.jsプロジェクトをCloud Runに乗せてデプロイするぜ!(GCPの新しいサービス)
Google Cloud Next'19で新しい発表がありましたね
AWS一筋の人は浮気したくなるじゃない?^^(クラウド戦争の種を撒こう)
Cloud Runとは
Google Cloud Next’19で発表された新サービス
https://cloud.withgoogle.com/next/sfコンテナ単位でサーバーレスの実行環境です。一番の目的としてはこれだと思います。
あらゆる言語で書かれたカスタムアプリケーションのサーバーレスでの運用、そして多様な環境にまたがる互換性の確保を目的としている。
ほほっ!!!!使うもの
Nuxt.js (SSR必須) Docker (クジラかな?)
gcloud (gcpのcli)
GCPのサービス:
Cloud Run (今回の主役) Container Registry (GCPのプロジェクトのコンテナリポジトリ管理)1.Nuxt.jsプロジェクト作成
まずはNuxt.jsのプロジェクト設定ですね。
Choose rendering modeはUniversal以外には好きなの選んで大丈夫です。npx create-nuxt-app nuxt-cloudrun > Generating Nuxt.js project in /Users/jakushin.cho/Projects/nuxt-cloudrun ? Project name nuxt-cloudrun ? Project description My dandy Nuxt.js project ? Use a custom server framework express ? Choose features to install (Press <space> to select, <a> to toggle all, <i> to invert selection) ? Use a custom UI framework vuetify ? Use a custom test framework none ? Choose rendering mode Universal <--- SSR ? Author name jakushin ? Choose a package manager npmローカルで起動して、問題はないかをチェックしましょう
npm run dev2.Dockerファイルの設定
プロジェクトディレクトリでdockerfileを作成します、内容はこちら
FROM node:10 WORKDIR /usr/src/app ENV PORT 8080 ENV HOST 0.0.0.0 COPY package*.json ./ RUN npm install --only=production # Nuxtプロジェクトのコードをコンテナにコピー COPY . . # prodビルト、サーバ起動 RUN npm run build CMD npm startファイル作成後、以下のコマンドでdocker image作成
> docker build ./ .. .. .. (ログ省略) ---> 317bd77abc49 Successfully built 317bd77abc49 <--- 作成したイメージID作成したイメージIDで、docker runでnuxtのアプリを起動チェック(スキップ可)
> docker run -p 8080:8080 317bd77abc49 nuxt-cloudrun@1.0.0 start /usr/src/app cross-env NODE_ENV=production node server/index.js 01:13:09 READY Server listening on http://0.0.0.0:8080起動後、0.0.0.0:8080にアクセスし、先程のvuetify+nuxtの画面が表示されたらOK!
動いているコンテナを消し忘れずですね。
> docker kill be0d7f77e4313.Container Registry (GCP)にコンテナイメージをpush
GCPでプロジェクトを作成しのが前提です。Cloud Container Registryを有効にしてください。まずdockerイメージにtag付けましょう。分かりやすくGCPのContainer Registryに統一しましょう。
GCPのコンテナホスト名 プロジェクト名 dockerイメージ名(任意) > docker tag 317bd77abc49 [us.gcr.io]/[myprojectid]/[nuxt-cloudrun]push先は同じURLでいいので、GCPのコンテナにpush!!!!
> docker push [us.gcr.io]/[myprojectid]/[nuxt-cloudrun]4.Cloud Run Beta(GCP)
有効にしてくださいね。
CREATE SERVICEをクリックしてで新規作成しましょう。
サービス作成画面でコンテナイメージのURLの右の「選択」ボタンをクリックします。
Container Registryに上げたnuxt-cloudrunイメージを選びます。
一般のユーザに公開したいならば、認証の未認証の呼び出しを許可を選び、「作成」ボタンをクリックします
成功した画面です
ログの方の出力はlocalのnuxt.jsのプロジェクトのログが一致しているの確認できます。
やったー!コンテナをサーバーレスにできたぜ!!!
日本語が下手くそな僕がまとめようとしても、まとまれないのまとめ
コンテナをサーバーレス化にして、ますますマイクロサービスの時代の流れを感じましたね!
以上!(無責任)
..
..
もう少し書きます。
cloud functionでサーバーレス、cloud runでコンテンをサーバーレス
インフラのことを気にしたくなければ、GCPは凄くいい選択肢ではないか。料金はこちら
https://cloud.google.com/run/pricing
試しで作ったサービスの消し忘れを注意してくださいね。
- 投稿日:2019-04-11T04:07:25+09:00
気持ちいいRuby/Ruby on Rails開発環境を作ったので解説(Mac/Win両対応)
hayakasa/docker-vagrant-template-rails
以下の要件を満たすRuby/Ruby on Railsの開発・実行環境を環境を作成しました。
- ホストOSの環境を極力汚さないこと
- 必要最低限の手順で環境構築できること
- 実行環境のバージョンを管理する手間を極力省くこと
- ソースコードを共有ディレクトリでマウントし、編集後に即時反映されること
- Dockerコンテナ側からファイル操作が可能なこと(bundle install、tmp内のファイル作成など)
- Mac・Windowsどちらでも可能な限り同じ手順で構築し動作すること
rvm、rbenvなどで実行環境のバージョン管理をすることが手間に感じていたのでDockerを採用することを決めたのですが、公式で配布されているDocker Desktop for Mac/Windowsにはソースコードを即時反映できるようにマウントした場合に実行速度が遅くなるなどの問題があります。
この問題を解決するため、ホストOSとDockerコンテナの間にVagrantで管理するVMを挟み、共有ディレクトリをNFSでマウントすることによって実行速度を犠牲にせずにアプリ開発ができる環境を作りました。前提アプリケーションのインストールや使い方は下記GitHubリポジトリのREADMEを参照ください。
hayakasa/docker-vagrant-template-railsこちらでは、少し突っ込んだ解説を行います。
NFSについて
Vagrantfileの以下の設定で共有ディレクトリをNFSマウントしています。
Vagrantfileconfig.vm.synced_folder ".", "/vagrant-nfs",type:"nfs" #DocRootをvagrant-nfsという名前でNFSマウントMacの場合
Macでは標準でNFSサーバーが準備されているので以下のコマンドで有効化します。
YourPC$ sudo touch /etc/exports #nfsd設定を保存するファイルを作成 YourPC$ sudo nfsd enable #nfsdの有効化Windowsの場合
WindowsではVagrantのプラグインを使うことによってNFSサーバーを立てずにNFSでマウントができるためそちらを使用します。
YourPC$ vagrant plugin install vagrant-winnfsdvagrant-bindfsプラグインについて
NFSでマウントした共有ディレクトリはホストOSのユーザーがownerになっているので、bindfsでvagrantユーザーがownerになるようにマウントし直します。
Vagrantfileconfig.bindfs.bind_folder "/vagrant-nfs", "/vagrant" #vagrant-nfsをvagrantという名前でbindfsマウントvagrant-hostsupdaterプラグインについて
vagrant upでVMを起動するときにhostsファイルにホスト名の登録を行います。これによってホスト名でアプリケーションにアクセスすることができるようになります。
(hostsを操作するためWindowsではコマンドプロンプト・PowerShellを管理者権限で実行する必要があります)Vagrantfileconfig.vm.hostname = "myapp.localhost"ポートフォワーディングについて
以下の設定によって一般的に使用されるポートでホストOSからアクセスができるようにしています。
docker-compose.ymlservices: db: ports: - "5432:5432" #例:PostgreSQLの場合。Dockerコンテナの5432番をVMの5432番にポートフォワーディング app: command: bundle exec rails s -p 3000 -b '0.0.0.0' --no-dev-caching #rails s を3000番ポートで実行 ports: - "80:3000" #Dockerコンテナの3000番ポートをVMの80番にポートフォワーディングVagrantfileconfig.vm.network "forwarded_port", guest: 80, host: 80 #VMの80番をホストOSの80番にポートフォワーディング config.vm.network "forwarded_port", guest: 5432, host: 5432 #VMの5432番をホストOSの5432番にポートフォワーディングデータベースのvolumeについて
以下の設定によってデータベースの内容はVM内で永続化しています。したがってVMのイメージ自体を削除しない限り、Dockerコンテナを破棄してもデータベースの中身は保持されます。
docker-compose.ymlservices: db: volumes: - /data/db:/var/lib/postgresql/data #例:PostgreSQLの場合 Dockerコンテナの/var/lib/postgresql/dataをVMの/data/dbに保存します
- 投稿日:2019-04-11T01:55:29+09:00
データ連携の平成世代sftpクライアントだってコンテナになりたい令和元年のtips
俺です
昭和の僕が思い浮かぶ外部連携といえばftpです。全銀tcp/ip最高みたいな話です。
sftpクライアントなコンテナを使い、他のサーバからファイルをgetしてから後続のシェルコマンドやスクリプトで何かしたい。というアレがアレなものをdocker-composeのvolumeを使い、dockerホストにsftpで取得したファイルを保管して動かすtipsですsftpクライアント用のコンテナにはこちらを使います。
定義
- docker-compose.yml
sftpコマンドのワンライナーをcommandに埋めるのはしんどいのでbatchfileをreadします.
version: "3" services: sftpclient: image: chartedcode/alpine-sftp-client command: sshpass sftp -i /tmp/.ssh/id_rsa -oStrictHostKeyChecking=no -b /tmp/sftp_job_script sftpsaikou@127.0.0.1 volumes: - .:/tmp:ro - /mnt/data:/mnt/data subsequent_job_a: image: ubuntu:latest command: ls -l /mnt/data && echo "sftpは最高だぜ" depends_on: - sftpclient volumes: - /mnt/data:/mnt/data
- sftp_job_script
docker-composeと同一ディレクトリにbatchfileを作ります。(パス分けてもいいんですけども)
ls lcd /mnt/data get unko.csv bye実行例
$ docker-compose -f docker-compose.yml up Starting jobuser_sftpclient_1 ... done Recreating jobuser_cron_job_1 ... done Attaching to jobuser_sftpclient_1, jobuser_cron_job_1 sftpclient_1 | sftp> ls sftpclient_1 | sftp> lcd /mnt/data sftpclient_1 | sftp> get unko.csv sftpclient_1 | sftp> bye jobuser_sftpclient_1 exited with code 0 cron_job_1 | total 0 cron_job_1 | -rw-r--r-- 1 root root 0 Apr 10 16:49 unko.csv cron_job_1 | sftpは最高だぜ jobuser_cron_job_1 exited with code 0良いデータ連携ライフを!
- 投稿日:2019-04-11T01:43:30+09:00
dockerでiOSの疑似脱獄
iOSでは、制約に縛られることがかなり多いわけですが、dockerを使って、iOSを乗っ取れるかもしれない、などと夢想しています。
たまたまiPhoneのマイク、スピーカーを共有する必要のあるプロジェクトにかかわっていまして、アイデアの一つとして、可能性を追いかけたく思っています。
皆様のご意見等いただければ幸いです。
- 投稿日:2019-04-11T01:23:05+09:00
DockerのGUI管理ツール調査
Kitematic
GitHubの最終更新は、2019年2月4日
ライセンスは、Apache License 2.0
0.17.7 (2019年2月4日)読み方は、カイトマティック
Windows、および、macOSでDockerの導入・操作ができるツールRancher
GitHubの最終更新は、2019年4月10日
ライセンスは、Apache License 2.0
2.2.2-rc8 (2019年4月10日)読み方は、ランチャー?
公式サイト
GitHub
Rancher 2.x image
Rancher 1.x image
RANCHER JP
DockerのGUI管理ツール Rancherを試してみる
話題のKubernetesをRancher2.0で 便利に使う!
Rancherでコンテナサービスをデプロイしてみる
RancherでKubernetesクラスタを作る
Rancher2.1でKubernetes環境を構築する
Rancher2.0を使って超高速にkubernetesクラスタを構築した時のメモ
シングルノードにkubernetesとRancher 2.0を導入して、コンテナ管理してみた
Rancher 2.0で複数のKubernetes環境を管理してみる
Rancher/Kubernetes入門ハンズオン資料~第2回さくらとコンテナの夕べ #さくらの夕べ
Rancher 2.0 入門!!! Kubernetesクラスタの可視化!!!
複数の物理ホストの Debian9 上に Kubernetes (k8s) クラスタを Rancher で立ち上げる
Rancherでコンテナ化に挫折しました
Rancher 構築メモPortainer
GitHubの最終更新は、2019年4月8日
ライセンスは、zlib License
利用条件が緩いzlibライセンスについて
0.10.1 (2016年4月3日)読み方は、ポーテイナー?
Windows、Linux、macOS公式サイト
GitHub
Portainer - シンプルなDockerイメージ/コンテナ管理
Docker初心者でも安心!Portainerを使ってイメージやコンテナを管理する
Portainer でできること
Portainerを利用して個人環境のコンテナ管理をする
portainerであれこれ試した話
portainerを使ってローカル環境でDockerコンテナの管理
自宅での技術検証がより楽しくなる? portainer で Docker コンテナ管理
[2019年1月版]WSL + Ubuntu + Docker で Portainer
portainer(CentOS7)構築メモ
CoreOSとPortainerで簡単コンテナ管理
Docker のイメージやコンテナをGUIで管理できる Portainer のインストール
Docker を管理する Webアプリ Portainer を Docker Compose で起動する
Docker 管理ツール Portainer を導入するDocker
# portainerが動いているDockerホストを管理する場合(Linux or Mac) $ docker run -d -p 9000:9000 -v /var/run/docker.sock:/var/run/docker.sock portainer/portainer # リモートのDockerホストを管理する場合 $ docker run -d -p 9000:9000 portainer/portainerPanamax-ui
GitHubの最終更新は、2016年2月24日
ライセンスは、Apache License 2.0
0.2.21 (2015年7月22日)GitHub
centurylink/panamax-ui
Panamax - WebベースのDocker管理
コンテナ管理ツール「Panamax」をCoreOSと組み合わせて使ってみよう
Panamax をもっと簡単に Vagrant だけで使いたいsimple-docker-ui
GitHubの最終更新は、2017年8月8日
ライセンスは、MIT License
0.5.5 (2017年2月21日)GitHub
Dockerのイメージ、コンテナ管理を手軽にしてくれる「Simple Docker UI」レビュー
ブラウザ経由のDocker管理UI Simple Docker UI
- 投稿日:2019-04-11T00:55:13+09:00
Windows 10 Educationにしてみた
事の発端
周りの人を含めてみんなDockerやってるし自分も流行に乗りたいなーDockerでドカドカしたいなー
→Docker for Windowsを使うためにはHyper-Vが必要
→Windows 10 HomeではHyper-Vを有効化できない
というところまで調べて諦めていたのですが、MicrosoftのMicrosoft Imagineというプログラムの一環で学生であればWindows 10 Educationが無料で使える(=Hyper-Vの有効化ができる)とのことだったので、実際にやってみました。Azure for Studentのアカウントを作成する
はじめに、Microsoftのアカウントを持っていない人は以下のリンクから新規作成を行いましょう。https://account.microsoft.com/account?lang=ja-JP
次に、https://azure.microsoft.com/ja-jp/free/students/ このページへアクセスし、今すぐアクティブ化をクリックします。
すると以下のようなページに飛ぶので、自分の学校でのメールを入力していきます。
メールアドレスを2回入力したら教育機関ステータスの確認をクリックし、きちんと学校の有効なメールアドレスであることを証明します。(自分の場合はメールが届きそのメールに添付されていたリンクを押して証明しました。)
(学生であってもメールアドレスを取得することがない学校の場合は取得できるかわからないです・・・)最後に電話番号で本人確認(?)を行うと完了です。(画面に従うだけなので特に難しいところはないと思います。)
以下の画面に到達すれば成功です。
Windows 10 Education用のライセンスキーの入手
上記の画面にたどり着いたらそのまま右に表示されているソフトウェアを取得の横の方にあるすべて表示をクリックし、一覧の中からWindows 10 Educationを探します。(検索を使うといいかもしれません)
その後キーを表示し、コピーします。
キーをコピーしたら次は左下のスタートメニューから設定を開きます。設定→更新とセキュリティ→ライセンス認証へ進み、プロダクトキーを変更しますから先ほどコピーしたプロダクトキーをペーストし次へを押しプロダクトキーを更新します。
するとWindowsのインストールが始まるので、しばらく待って再起動したら成功です。PCのプロパティから現在のWindowsのバージョンを確認してみます。
無事にWindows 10 Educationに変更できていることが確認できました。また、事の発端であったHyper-Vも有効にできることが確認できました。
まとめ
これで自分もDockerでドカドカできるぞー!
Qiitaの投稿初めてなので読みづらかったり変なところがあったらごめんなさい。Hyper-Vの有効化からDockerの導入はたくさんの人がわかりやすく説明してくださっているのでここでは割愛させていただきます。
この記事が少しでもお役に立てれば光栄です。


























