Raspberry Pi 3 をアクセスポイントにする

公式のサイトのACCESS-POINTの "Using the Raspberry Pi as an access point to share an internet connection (bridge)" を参考に Raspberry Pi 3 をアクセスポイントにしました。

$ sudo -s
# apt-get update
# apt-get upgrade
# apt-get install hostapd bridge-utils
# systemctl stop hostapd

/etc/dhcpcd.conf の最後に、denyinterfaces wlan0denyinterfaces eth0 を追記します。

ブリッジを追加します。

# brctl addbr br0

br0 に eth0 を接続します。

# brctl addif br0 eth0

/etc/network/interfaces に追記します。

# Bridge setup
auto br0
iface br0 inet manual
    bridge_ports eth0 wlan0
    bridge_stp on

/etc/hostapd/hostapd.conf を記述します。

interface=wlan0
bridge=br0
#driver=nl80211
ssid=NameOfNetwork
hw_mode=g
channel=7
wmm_enabled=0
macaddr_acl=0
auth_algs=1
ignore_broadcast_ssid=0
wpa=2
wpa_passphrase=AardvarkBadgerHedgehog
wpa_key_mgmt=WPA-PSK
wpa_pairwise=TKIP
rsn_pairwise=CCMP
country_code=JP

ここまでの設定でリブートすれば動くように書かれていましたが、試しに、hostapd /etc/hostapd/hostapd.conf を実行してみると、AP-DISABLED となっていました。 rfkill list を実行すると以下のように表示されました。

0: phy0: Wireless LAN
    Soft blocked: yes
    Hard blocked: no
1: hci0: Bluetooth
    Soft blocked: yes
    Hard blocked: no

そこで、rfkill unblock 0 として、Wireless LAN のブロックを解除しました。

最後に、/etc/default/hostapd の DAEMON_CONF="" のところを次のように修正して、reboot します。

DAEMON_CONF="/etc/hostapd/hostapd.conf"

Microservices と DDD

本記事はドメイン駆動設計 Advent Calendar 2018 - Qiitaの4日目の記事です。

3日目は、bigwheelさんの「集約の境界と整合性の維持の仕方に悩んで2ヶ月ぐらい結論を出せていない話」でした。

5日目は、yoskhdiaさんの「エンティティの同一性を表現するためにequalsをオーバーライドすべきか否か」です。

Microservices の利点

  • 技術異質性
  • 回復性
  • スケーリング
  • デプロイの容易性
  • 組織面の一致
  • 合成可能性
  • 交換可能にするための最適化

Monoliths, Microliths での境界づけられたコンテキストの統合

Monoliths

Monoliths なアプリケーションに複数の境界づけられたコンテキストを統合するケースでは、共有ライブラリや、モジュールによって 分散コンピューティングで遭遇する煩わしい問題の多くを回避できます。

Monoliths なアプリケーションの欠点は、変更した場合にアプリケーション全体をデプロイしなおす必要がありデプロイ容易性に欠けるという点です。 このことから頻繁なデプロイを行うことが少なく、時間の経過とともに技術的負債が蓄積され、変更がさらに困難となっていきます。

Microliths

Monoliths なアプリケーションのケースでも、必ずしも一つのアプリケーションで構成されるわけではなく、日次、月次、年次等のようなバッチ処理アプリケーションとWebアプリケーションのように、複数のアプリケーションに境界づけられたコンテキストが統合されます。

これをさらに細かく分割して Microservices と似た構成のアプリケーションに分割することもできます、分割したアプリケーションで次のような問題が発見されることがあります。

  • アプリケーション間の結合度が高く、いずれかのアプリケーションの障害により分割した他のアプリケーションに影響を与える
  • 類似のロジックが分散していて、あるアプリケーションの変更を、他のアプリケーションでも行う必要がある

結果として、分割したアプリケーション単体でのデプロイは困難となり、複数のアプリケーション、最悪の場合は、すべてのアプリケーションを同時期にデプロイしなければならなくなります。

このように分割されたアプリケーションは Microliths と呼ばれます。

Microservices

実践ドメイン駆動設計から、Microservices としての利点を満たすアプリケーションにとって特に重要なポイントをピックアップしてみます。

第2章 ドメインサブドメイン、境界づけられたコンテキスト

Microservices ではアプリケーションと組織面の一致が必要です。したがって、ドメインサブドメインや境界づけられたコンテキストと組織面の一致がないと、不要なドメイン知識まで取り込むことになったり、ドメインの知識を、外部のコンテキスト - つまりは他の Microservices - に依存しなければならなくなり、自律的なサービスを実現することができなくなります。

第13章 境界づけられたコンテキストの統合

Microservices として自律的なサービスを担保するためには、境界づけられたコンテキストの統合にメッセージングが最も有力な候補となります。

第14章 アプリケーション

Microservices に統合する、複数の境界づけられたコンテキストは組織面と一致させる必要があります。

まとめ

Microservices に分割したアプリケーションがうまく機能しないというのを見聞きすることがありますが、これは、Microservices だからということではなく、 境界づけられたはずのコンテキストの境界があいまいであったり、ドメインサブドメインについての考察が十分ではないことが原因の多くをしめているのではと考えています。 Monoliths であればそういった誤りは技術的負債として将来に繰延べされますが、Microservices の場合は初期にこのような問題が発見されるため、設計に対するフィードバックを早めることができるという利点もあると考えています。

参考文献

他アカウントの CodeCommit を使用した CodePipeline

開発アカウントに CodeCommit を使用して、プロダクションアカウントでビルドやデプロイを行うためのメモ。

f:id:section27:20180924032104p:plain

1. プロダクションアカウント

1-1. CodePipeline のサービスロールのためのポリシーを作成する

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "s3:GetObject",
                "s3:GetObjectVersion",
                "s3:GetBucketVersioning"
            ],
            "Resource": "*",
            "Effect": "Allow"
        },
        {
            "Action": [
                "s3:PutObject"
            ],
            "Resource": [
                "arn:aws:s3:::codepipeline*",
                "arn:aws:s3:::elasticbeanstalk*"
            ],
            "Effect": "Allow"
        },
        {
            "Action": [
                "codecommit:CancelUploadArchive",
                "codecommit:GetBranch",
                "codecommit:GetCommit",
                "codecommit:GetUploadArchiveStatus",
                "codecommit:UploadArchive"
            ],
            "Resource": "*",
            "Effect": "Allow"
        },
        {
            "Action": [
                "codedeploy:CreateDeployment",
                "codedeploy:GetApplicationRevision",
                "codedeploy:GetDeployment",
                "codedeploy:GetDeploymentConfig",
                "codedeploy:RegisterApplicationRevision"
            ],
            "Resource": "*",
            "Effect": "Allow"
        },
        {
            "Action": [
                "elasticbeanstalk:*",
                "ec2:*",
                "elasticloadbalancing:*",
                "autoscaling:*",
                "cloudwatch:*",
                "s3:*",
                "sns:*",
                "cloudformation:*",
                "rds:*",
                "sqs:*",
                "ecs:*",
                "iam:PassRole"
            ],
            "Resource": "*",
            "Effect": "Allow"
        },
        {
            "Action": [
                "lambda:InvokeFunction",
                "lambda:ListFunctions"
            ],
            "Resource": "*",
            "Effect": "Allow"
        },
        {
            "Action": [
                "opsworks:CreateDeployment",
                "opsworks:DescribeApps",
                "opsworks:DescribeCommands",
                "opsworks:DescribeDeployments",
                "opsworks:DescribeInstances",
                "opsworks:DescribeStacks",
                "opsworks:UpdateApp",
                "opsworks:UpdateStack"
            ],
            "Resource": "*",
            "Effect": "Allow"
        },
        {
            "Action": [
                "cloudformation:CreateStack",
                "cloudformation:DeleteStack",
                "cloudformation:DescribeStacks",
                "cloudformation:UpdateStack",
                "cloudformation:CreateChangeSet",
                "cloudformation:DeleteChangeSet",
                "cloudformation:DescribeChangeSet",
                "cloudformation:ExecuteChangeSet",
                "cloudformation:SetStackPolicy",
                "cloudformation:ValidateTemplate",
                "iam:PassRole"
            ],
            "Resource": "*",
            "Effect": "Allow"
        },
        {
            "Action": [
                "codebuild:BatchGetBuilds",
                "codebuild:StartBuild"
            ],
            "Resource": "*",
            "Effect": "Allow"
        },
        {
            "Effect": "Allow",
            "Action": [
                "devicefarm:ListProjects",
                "devicefarm:ListDevicePools",
                "devicefarm:GetRun",
                "devicefarm:GetUpload",
                "devicefarm:CreateUpload",
                "devicefarm:ScheduleRun"
            ],
            "Resource": "*"
        }
    ]
}

1-2. CodePipeline のサービスロールを作成する

CodePipeline サービスのロールを作成する

1-3. IAMの暗号化キーを作成する

  • IAM から 暗号化キー を選択して、使用するリージョンで キーの作成 を選択する
  • エイリアスと説明の作成で、エイリアス を入力し 次のステップ を選択する
  • タグの追加で必要に応じてタグを追加し、次のステップ を選択する
  • キーの使用アクセス許可の定義 の キー管理者 を必要に応じて設定し、次のステップ を選択する
  • キーの使用アクセス許可の定義 の このアカウント で 1-2 の手順で作成した CodePipeline のサービスロールを選択する、 外部アカウント で 外部アカウントの追加 を選択して開発アカウントIDを入力する
  • キーポリシーのプレビューで 完了 を選択する

1-4. CodePipeline のサービスロールに暗号化キーのポリシーを追加する

1-2 の手順で作成した CodePipeline のロールに 1-3 の手順で作成した暗号化キーの ARN をリソースに設定して作成したポリシーをアタッチする

{
    "Version": "2012-10-17",
    "Statement": {
        "Effect": "Allow",
        "Action": [
            "kms:*"
        ],
        "Resource": [
            "arn:aws:kms:ap-northeast-1:${ProductionAccount}:key/2222222-3333333-4444-556677EXAMPLE"
        ]
    }
}

1-5. CodeBuild のサービスロールのためのポリシーを作成する

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "codebuild:*",
                "iam:PassRole",
                "logs:FilterLogEvents",
                "logs:GetLogEvents",
                "logs:CreateLogStream",
                "logs:CreateLogGroup",
                "logs:PutLogEvents",
                "s3:CreateBucket",
                "s3:GetObject",
                "s3:List*",
                "s3:PutObject"
            ],
            "Resource": "*",
            "Effect": "Allow"
        }
    ]
}

1-6. CodeBuild のサービスロールを作成する

CodeBuild サービスのロールを作成し、1-5 の手順で作成した CodeBuild のポリシーと 1-4 の手順で作成したポリシーをアタッチする

2. 開発アカウント

2-1. CodeCommit にクロスアカウントアクセスのためのポリシーを作成する

1-3 の手順で作成した暗号化キーの ARN を設定して、 クローンしたイメージを暗号化して CodePipeline の S3 に PutObject するためのポリシーを作成する。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
              "codecommit:BatchGetRepositories",
              "codecommit:Get*",
              "codecommit:GitPull",
              "codecommit:List*",
              "codecommit:CancelUploadArchive",
              "codecommit:UploadArchive",
              "s3:*"
            ],
            "Resource": "*"
        },
        {
           "Effect": "Allow",
            "Action": [
                "kms:*"
            ],
            "Resource": [
                "arn:aws:kms:ap-northeast-1:${ProductionAccount}:key/2222222-3333333-4444-556677EXAMPLE"
            ]
        }
    ]
}

2-2. CodeCommit のロールを作成する

  • IAM から ロール を選択し ロールの作成 を選択する
  • 別のAWSアカウント を選択し、アカウントID にプロダクションアカウントのアカウントIDを入力し、次のステップ:アクセス権限 を選択する
  • 2-1 の手順で作成したポリシーをアタッチし、次のステップ:確認 を選択する
  • ロール名を入力し、ロールの作成 を選択する

2-3. CodeCommit を作成する

CodeCommit を作成する。CodeCommit はあらかじめ作成しておいてもよい。

3. プロダクションアカウント

3-1. CodePipeline のサービスロールに開発アカウントのポリシーを追加

CodePipeline に開発アカウントの CodeCommit のロールにアクセスするポリシーを作成しアタッチする

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "sts:AssumeRole"
            ],
            "Resource": [
                "arn:aws:iam::${DevelopAccount}:role/${CodeCommitRoleName}"
            ]
        }
    ]
}

3-2. CodePipeline の Artifact Store となる S3 Bucket を作成する

codebuild.amazonaws.com サービスと開発アカウントの CodeCommit ロールからアクセスされる CodePipeline で使う S3 Bucket を作成する。

Key Description
BucketName CodePipeline が使用するバケット
CodeCommitRoleName 2-2 の手順で作成したロール名
DevelopAccount 開発アカウントID
AWSTemplateFormatVersion: '2010-09-09'
Parameters:
  BucketName:
    Type: String
  CodeCommitRoleName:
    Type: String
  DevelopAccount:
    Type: String
Resources:
  S3Bucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Ref BucketName
  BucketPolicy:
    Type: AWS::S3::BucketPolicy
    Properties:
      Bucket: !Ref S3Bucket
      PolicyDocument:
        Statement:
        - Action: s3:*
          Effect: Allow
          Resource:
          - !Sub arn:aws:s3:::${BucketName}
          - !Sub arn:aws:s3:::${BucketName}/*
          Principal:
            Service:
            - codebuild.amazonaws.com
            AWS:
            - !Sub arn:aws:iam::${DevelopAccount}:role/${CodeCommitRoleName}

3-3. CodeBuild

Key Description
CacheLocation CodeBuild のキャッシュが使用するバケット
CodeBuildRoleName 1-6 の手順で作成したロール名
Image CodeBuildに使用するコンテナ名
Name CodeBuild名
AWSTemplateFormatVersion: '2010-09-09'
Parameters:
  CacheLocation:
    Type: String
  CodeBuildRoleName:
    Type: String
  Image:
    Type: String
  Name:
    Type: String
Resources:
  CodeBuild:
    Type: AWS::CodeBuild::Project
    Properties:
      Artifacts:
        Type: CODEPIPELINE
      Cache:
        Location: !Sub ${CacheLocation}/ivy2
        Type: S3
      Description: !Ref Name
      EncryptionKey: arn:aws:kms:ap-northeast-1:${ProductionAccount}:key/2222222-3333333-4444-556677EXAMPLE
      Environment:
        ComputeType: BUILD_GENERAL1_SMALL
        Image: !Ref Image
        EnvironmentVariables:
        - Name: BUCKET_NAME
          Value: !Ref CacheLocation
        PrivilegedMode: true
        Type: LINUX_CONTAINER
      Name: !Ref Name
      ServiceRole: !Sub arn:aws:iam::${AWS::AccountId}:role/${CodeBuildRoleName}
      Source:
        Type: CODEPIPELINE

3-4. CodePipeline

Key Description
BucketName 3-2 の手順で作成したバケット
CodeCommitRoleName 2-2 の手順で作成したロール名
CodePipelineRoleName 1-2 の手順で作成したロール名
DevelopAccount 開発アカウントID
Name CodePipeline名
RepositoryName 2-3 の手順で作成した CodeCommit リポジトリ
AWSTemplateFormatVersion: '2010-09-09'
Parameters:
  BucketName:
    Type: String
  CodeCommitRoleName:
    Type: String
  CodePipelineRoleName:
    Type: String
  DevelopAccount:
    Type: String
  Name:
    Type: String
  RepositoryName:
    Type: String
Resources:
  CodePipeline:
    Type: AWS::CodePipeline::Pipeline
    Properties:
      ArtifactStore:
        EncryptionKey:
          Id: arn:aws:kms:ap-northeast-1:${ProductionAccount}:key/2222222-3333333-4444-556677EXAMPLE
          Type: KMS
        Location: !Ref BucketName
        Type: S3
      Name: !Ref Name
      RoleArn: !Sub arn:aws:iam::${AWS::AccountId}:role/${CodePipelineRoleName}
      Stages:
      - Actions:
        - ActionTypeId:
            Category: Source
            Owner: AWS
            Provider: CodeCommit
            Version: 1
          Configuration:
            PollForSourceChanges: false
            RepositoryName: !Ref RepositoryName
            BranchName: master
          Name: source
          OutputArtifacts:
          - Name: MyApp
          RoleArn: !Sub arn:aws:iam::${DevelopAccount}:role/${CodeCommitRoleName}
        Name: source
      - Actions:
        - ActionTypeId:
            Category: Build
            Owner: AWS
            Provider: CodeBuild
            Version: 1
          Configuration:
            ProjectName: !Ref Name
          InputArtifacts:
          - Name: MyApp
          OutputArtifacts:
          - Name: App
          Name: build
        Name: build

参考

ECR のイメージを別のアカウントの ECR に転送する

準備

$ pip install boto3
$ pip install docker

ECR から pull

import boto3
import base64
import docker

account_id = '123456789012'
region = 'ap-northeast-1'
name = '%s.dkr.ecr.%s.amazonaws.com/%s' % (account_id, region, 'example')

session = boto3.Session(
    profile_name = SWITCH_ACCOUNT_PROFILE,
    region_name = region
)

ecr = session.client('ecr')
authorization_token = ecr.get_authorization_token()['authorizationData'][0]
token = base64.b64decode(authorization_token['authorizationToken']).split(':')
user = token[0]
pwd = token[1]
auth_cred = { 'username': user, 'password': pwd }

client = docker.from_env()
client.images.pull(name, auth_config = auth_cred)

転送先の ECR 用に tag を設定

import docker

src_account_id = '123456789012'
dist_account_id = '210987654321'
region = 'ap-northeast-1'

src = '%s.dkr.ecr.%s.amazonaws.com/%s' % (src_account_id, region, 'example')
dist = '%s.dkr.ecr.%s.amazonaws.com/%s' % (dist_account_id, region, 'example')

client = docker.from_env()
images = client.images.list(name = src)
for image in images:
    for tag in image.tags:
        t = tag.split(':')[1]
        image.tag(dist, t)

別のアカウントの ECR に push

import boto3
import base64
import docker

account_id = '210987654321'
region = 'ap-northeast-1'

session = boto3.Session(
    profile_name = SWITCH_ANOTHER_ACCOUNT_PROFILE,
    region_name = region
)

name = '%s.dkr.ecr.%s.amazonaws.com/%s' % (account_id, region, 'example')
ecr = session.client('ecr')
authorization_token = ecr.get_authorization_token()['authorizationData'][0]
token = base64.b64decode(authorization_token['authorizationToken']).split(':')
user = token[0]
pwd = token[1]
auth_cred = { 'username': user, 'password': pwd }
client = docker.from_env()
images = client.images.list(name = name)
for image in images:
    for tag in image.tags:
        client.images.push(tag, auth_config = auth_cred)

Excel 2016 for Mac でシート名のタブが表示されなくなったとき

ある日の夕方、わたしはパニックになっていた。

通常なら、エクセルの画面の下にはシート名がこんな感じで表示されていて、目的のシートを編集するだけだと思っていたからだ。

f:id:section27:20180902152241p:plain

ところが、実際に操作をしようとすると、なんとシート名が表示されていない。目的のシートはどこへ消えてしまったのだ。わからん、今日中になんとかしなければと思いつつもどうにもできない。わたしは編集ができなかったことを伝えてその日は帰るしかなかった。

f:id:section27:20180902152302p:plain

後日、設定がおかしかっただけというような話を聞いたので、あらためてググってみた。

まずは、エクセルのメニューから、「環境設定」を選んでみる。

f:id:section27:20180902152316p:plain

次に、「表示」というのを選んでみる。

f:id:section27:20180902152328p:plain

なるほど、「シート見出し」というところにチェックが入っていない。 なら、話は簡単だ、この「シート見出し」とやらにチェックを入れればいいはずだと気づいた。

f:id:section27:20180902152340p:plain

これで、元通りシート見出しが表示されるようになって、目的の作業を完遂することができた。

Serverless Framework で Pseudo Parameters を使う

Serverless FrameworkAWSPseudo Parameters を使うのに少し悩んだのでメモとして残します。

うまくいったパターン

2通りの方法で定義しています(var1 と var2)。

service: hello
provider:
  name: aws
  runtime: nodejs8.10

custom:
  accountId: 
    Ref: 'AWS::AccountId'

functions:
  hello:
    handler: handler.hello
    environment:
      var1: ${self:custom.accountId}
      var2: 
        Ref: 'AWS::AccountId'

うまくいかないパターン

Serverless Framework では ${} のように囲まれた部分を、定義されている変数で置換しようとするためエラーになってしまいました。

service: hello
provider:
  name: aws
  runtime: nodejs8.10

functions:
  hello:
    handler: handler.hello
    environment:
      var1:
        Fn::Sub:
          '${Ref: AWS::AccountId}'

さんちか

神戸三宮の地下街に入るとかならず耳にするあの曲ってなんだろうとしらべてみた

ばんばひろふみさんの「風に乗って」だとわかった

CDはすでに廃盤

なんとか曲を手に入れられないかいろいろ調べたら

mora.jp で販売されていた

音楽ダウンロード・音楽配信サイト mora ~WALKMAN®公式ミュージックストア~

これでさんちかに行かなくてもいつでも聴ける