[Linux] “-f”オプションを付与してコマンドを実行しても、対話形式となってしまう場合がある

$ cp -f foo.conf bar.conf

サーバーによっては、例えばコマンド”cp”にエイリアス “alias cp=’cp -i'” (確認オプション)がデフォルト指定されている場合がある。
“-f”を利用する場合、コマンドの先頭に “\” もしくは “¥” を付けて実行させる。そうすることにより、エイリアスが無効になる。

$ ¥cp -f foo.conf bar.conf

AWS Elastic Beanstalkの拡張機能 “ebextensions” で “commands” (若しくはcontainer_commands)を利用する場合は、”¥” もしくは “\” を付与してはならない。Deploy自体が失敗してしまう為である。Amazon Linuxの場合は、エイリアスを無効にせずとも、”-f” オプションは有効となる。

[Elastic Beanstalk] commandsとcontainer_commandsの違い

commands

  • シェルコマンドを実行可能。
  • アルファベット順に処理される。
  • アプリケーションとWebサーバーがセットアップされ、アプリケーションのバージョンファイルが抽出される前に実行される。

container_commands

  • シェルコマンドを実行可能。
  • アプリケーションとWebサーバーがセットアップされ、アプリケーションバージョンのアーカイブが抽出された後、アプリケーションのバージョンが展開される前に実行される。
  • アルファベット順に処理される。
  • container_commands以外は、アプリケーションソースコードを抽出する前に実行される。
  • 1つのインスタンスが”AutoScaling Group”のleaderとなり、”leader_only: true”の場合、コマンドはleaderのインスタンスでしか実行されない。
packages:
  yum:
    tree: []
    dstat: []
    sysstat: []
    htop: []
    iotop: []

commands:
  install-mod_extract_forwarded:
    command: "sudo yum -y install mod_extract_forwarded --enablerepo=epel"
    ignoreErrors: true

container_commands:
  remove-webxml:
    command: "rm -f /etc/tomcat7/web.xml"
    ignoreErrors: true
  replace-webxml:
    command: "cp -f /tmp/deployment/application/ROOT/.ebextensions/web.xml /etc/tomcat7/"
    ignoreErrors: true
  overwrite-mod_extract_forwarded:
    command: "cp -f /tmp/deployment/application/ROOT/.ebextensions/mod_extract_forwarded.conf /etc/httpd/conf.d/mod_extract_forwarded.conf"
    ignoreErrors: true
    leader_only: true

files:
  "/opt/elasticbeanstalk/hooks/appdeploy/pre/server-setup.sh":
    mode: "000755"
    owner: root
    group: root
    content: |
      #!/bin/bash
      ## change hostname
      HOSTNAME="test.com"

      ## file parameter check
      if test "$HOSTNAME" = "" ;then
        echo "HOSTNAME Parameter error"
        exit 1
      fi
      echo "127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4 $HOSTNAME" > /etc/hosts
      echo "::1         localhost6 localhost6.localdomain6" >> /etc/hosts
      sed -i s/localhost.localdomain/$HOSTNAME/ /etc/sysconfig/network
      hostname $HOSTNAME

      ## change timezone
      cp -fp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime
      sed -i s@\"UTC\"@\"Asia/Tokyo\"@ /etc/sysconfig/clock

      ## stop iptables
      chkconfig iptables off
      chkconfig ip6tables off
      chkconfig --list | grep ip

      exit 0

Jenkinsサーバの構築

環境

環境 Ver.
Jenkins 2.58
Java 1.8

サーバー基本設定

Timezoneの変更

# 現在のTimezoneの確認 ※現在はUTC
$ strings /etc/localtimeTZif2TZif2UTC0

# オリジナルをバックアップ
$ cp /etc/localtime /etc/localtime.org

# Timezoneファイルの変更1
$ ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime

# Timezoneファイルの変更2
$ cp /etc/sysconfig/clock /etc/sysconfig/clock.org
$ vi /etc/sysconfig/clock
---
# ZONEの変更
ZONE="Asia/Tokyo"// falseにするとハードウェアのクロックもローカルタイムで設定されてしまう為、変更しない
UTC=true
---
# Timezoneが変更されていることを確認
strings /etc/localtime
TZif2
TZif2
JST-9

Swapの追加

$ dd if=/dev/zero of=/swapfile bs=1M count=1000
$ mkswap /swapfile
$ swapon /swapfile
swapon: /swapfile: 安全でない権限 0644 を持ちます。 0600 がお勧めです。
$ chmod 0600 /swapfile

Hostnameの設定

/etc/sysconfig/network

HOSTNAME={YOUR_HOSTNAME}

/etc/hosts

127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4 {YOUR_HOSTNAME}

文字コードの変更

/etc/sysconfig/i18n

LANG="ja_JP.UTF-8"

各種ツールのインストール

Gitのインストール

$ yum install git

Javaのインストール

# Javaのバージョン確認
$ java -version
java version "1.7.0_131"OpenJDK Runtime Environment (amzn-2.6.9.0.71.amzn1-x86_64 u131-b00)
OpenJDK 64-Bit Server VM (build 24.131-b00, mixed mode)

# Java1.8のインストール ※2017年5月現在、Java1.8でなければJenkins2.58が動作しない。
$ yum install java-1.8.0-openjdk-devel
Installed:
java-1.8.0-openjdk-devel.x86_64 1:1.8.0.121-0.b13.29.amzn1

# 既存のJavaからインストールしたJavaに向き先を変更する
$ alternatives --config java
$ java -versionopenjdk version "1.8.0_121"

EB CLIのインストール (デプロイ例として)

$ pip install --upgrade --user awsebcli
$ vi .bash_profile
---
//追加
export PATH=""~/.local/bin"":$PATH
---
$ source .bash_profile$ eb --version
EB CLI 3.10.1 (Python 2.7.1)

Jenkinsの設定

Jenkinsダウンロード

$ wget -O /etc/yum.repos.d/jenkins.repo http://pkg.jenkins-ci.org/redhat/jenkins.repo

# パッケージ署名チェック用のキーインポート
$ rpm --import https://jenkins-ci.org/redhat/jenkins-ci.org.key

# Jenkinsをインストール
$ yum install jenkins
Installing:jenkins noarch 2.58-1.1 jenkins 67 M
Transaction Summary

# ReverseProxy用にApacheのインストール
$ yum install httpd24

Jenkinsのポート変更

※デフォルトは8080

/etc/sysconfig/jenkins

JENKINS_PORT="8081"
$JENKINS_USER="root"

権限変更

Jenkins作業ディレクトリをroot権限へ変更する。

$ chown -R root:root /var/lib/jenkins
$ chown -R root:root /var/cache/jenkins
$ chown -R root:root /var/log/jenkins

# Jenkinsの再起動
$ service jenkins restart
$ ps -ef | grep jenkins

以降、Jenkins jobを全てroot権限で実行することとなる。

Digest認証の設定

# 認証可能なユーザの作成
$ htdigest -c /etc/httpd/conf/.htdigest Jenkins jenkins
Adding password for jenkins in realm Jenkins.
New password:
Re-type new password:

# Digest認証の反映を確認
$ less /etc/httpd/conf/.htdigest

ReverseProxyの設定

/etc/httpd/conf.d/jenkins.conf

# Canonicalise URLデコードを抑制
ProxyPass / http://localhost:8081/ nocanon
ProxyPassReverse / http://localhost:8081/
ProxyRequests Off
AllowEncodedSlashes NoDecode

<Proxy http://localhost:8081/*>
Order deny,allow
Allow from all
AuthType Digest
AuthName Jenkins
AuthUserFile /etc/httpd/conf/.htdigest
Require valid-user
</Proxy>
---

jenkins へ sudo の実行許可を付与

$ sudo visudo -f /etc/sudoers.d/cloud-init
$ sudo visudo
---
jenkins ALL=(ALL) NOPASSWD: ALL
---

設定の反映

# Apacheの再起動
$ service httpd restart

# Jenkinsの再起動
$ service jenkins restart

Jenkinsの起動

$ service jenkins start
# chkconfig コマンドを使用して、システムがブートするたびに Jenkinsが起動するように設定
$ chkconfig jenkins on

# 起動設定を確認
$ chkconfig --list jenkins

# ステータスを確認
$ service jenkins status

ブラウザから http://{public DNS} へアクセスし、Jenkinsへアクセスできることを確認。

Webアプリケーションの配置

$ mkdir {project_name}
$ git init
$ git add -A
$ git config user.name "xxx"
$ git config user.email "xxx@xxx"
$ git commit -m 'first commit'
$ git remote add origin https://github.com/xxx/xxx.git
$ git remote -v
origin https://github.com/xxx/xxx.git (fetch)
origin https://github.com/xxx/xxx.git (push)
$ git push -u origin develop
# もしくはclone$ git clone https://github.com/xxx/yyy

shell実行時、Gitのユーザー名/パスワードの入力を省略させるため以下を一旦、設定している。

~/.netrc

machine github.com
login {user_name}
password xxx

shellの設定

デプロイスクリプト 等。

Jenkinsファイルパス

  • 初期ログインパスワード記載ファイル: /var/lib/jenkins/secrets/initialAdminPassword
  • Jenkinsの環境設定ファイル: /etc/sysconfig/jenkins
  • Jenkins作業ディレクトリ: /var/lib/jenkins/*
  • Jenkinsのジョブ定義ファイル: /var/lib/jenkins/config.xml
  • Job格納ディレクトリ: /var/lib/jenkins/jobs
  • ビルド格納ディレクトリ: /var/lib/jenkins/jobs/{job}/builds/
  • ワークスペースディレクトリ: /var/lib/jenkins/workspace/
  • 起動スクリプト: /etc/init.d/jenkins
  • ログ: /var/log/jenkins/jenkins.log

Jenkins コマンド

# Jenkinsの起動
$ service jenkins start

# ステータスを確認
$ service jenkins status

# 起動確認
$ ps -elf | grep [j]enkins

Jenkins 再起動

“/safeRestart” へアクセスする。

Jenkinsのshell

Jenkinsの「シェルの実行」は、ビルド時に以下のオプション付きで実行される。

/bin/sh -xe
  • -x: スクリプト実行結果を表示。
  • -e: 実行後、exit codeが0以外の場合(エラー発生時)、終了させる。

Jenkinsのディスク容量不足

主にビルド履歴やプラグインがメモリを食う。

$ df -h
ファイルシス   サイズ  使用  残り 使用% マウント位置
devtmpfs         489M   56K  488M    1% /dev
tmpfs            497M     0  497M    0% /dev/shm
/dev/xvda1       7.8G  6.4G  1.4G   83% /

$ sudo du -sh /var/lib/jenkins/* | sort -h -r | head -20

ジョブ設定で、「古いビルドの破棄」オプションは30日以上、100ビルドまで保存等、適宜設定/保存する。

トラブルシューティング

ログ

“/log/all”の画面へアクセスする。

ログには何も出ていない場合は、以下のようにプロセスを停止し、フォアグラウンドでJenkinsを実行する。

$ service stop jenkins
$ java -jar /usr/lib/jenkins/jenkins.war

ジョブが表示されない。

Jenkinsの管理 > 設定の再読み込み を実行する。

“リバースプロキシの設定がおかしいようです。”と表示される。

  • URLエンコードの設定ミス
  • Jenkinsの設定ミス
    • Jenkinsの設定 > システムの管理 > Jenkins URL

プラグインのアンインストールが出来ない

Jenkins自体を再起動しないと、アンインストールが行われない。

参考サイト

関連記事

[AWS] Elastic BeanstalkのAutoscalingデプロイポリシー

バッチサイズやデプロイ中のヘルスチェックの動作を設定するオプション

[All at once]、[Rolling]、[Rolling with additional batch]、[Immutable]
・一度に全てのインスタンスへデプロイを反映させる時は”All at once”を選択する。
・デプロイ時にサービスに対しダウンタイムを発生させないようにするためには、”Rolling”を選択し1台ずつデプロイを行わせるようにする。
・全てのインスタンスを新しく構築し直す変更不可なデプロイは、”Immutable”を選択する。

例: Elastic Beanstalk config

ApplicationName: xxx
DateUpdated: 2017-08-18 05:22:49+00:00
EnvironmentName: dev
PlatformArn: arn:aws:elasticbeanstalk:ap-northeast-1::platform/Tomcat 7 with Java
  7 running on 64bit Amazon Linux/2.6.1
settings:
  AWSEBAutoScalingScaleDownPolicy.aws:autoscaling:trigger:
    LowerBreachScaleIncrement: '-1'
  AWSEBAutoScalingScaleUpPolicy.aws:autoscaling:trigger:
    UpperBreachScaleIncrement: '1'
  AWSEBCloudwatchAlarmHigh.aws:autoscaling:trigger:
    UpperThreshold: '90'
  AWSEBCloudwatchAlarmLow.aws:autoscaling:trigger:
    BreachDuration: '10'
    EvaluationPeriods: '1'
    LowerThreshold: '10'
    MeasureName: CPUUtilization
    Period: '10'
    Statistic: Average
    Unit: Percent
  AWSEBLoadBalancerSecurityGroup.aws:ec2:vpc:
    VPCId: null
  aws:autoscaling:asg:
    Availability Zones: Any
    Cooldown: '360'
    Custom Availability Zones: ap-northeast-1a
    MaxSize: '2'
    MinSize: '1'
  aws:autoscaling:launchconfiguration:
    BlockDeviceMappings: null
    EC2KeyName: xxx
    IamInstanceProfile: aws-elasticbeanstalk-ec2-role
    ImageId: ami-xxx
    InstanceType: t2.small
    MonitoringInterval: 5 minute
    RootVolumeIOPS: null
    RootVolumeSize: null
    RootVolumeType: null
    SSHSourceRestriction: tcp,xx,xx,xxx.xxx.xxx.xx/xx
    SecurityGroups: xxx
  aws:autoscaling:updatepolicy:rollingupdate:
    MaxBatchSize: '2'
    MinInstancesInService: '1'
    PauseTime: null
    RollingUpdateEnabled: 'true'
    RollingUpdateType: Health
    Timeout: PT30M
  aws:ec2:vpc:
    AssociatePublicIpAddress: null
    ELBScheme: public
    ELBSubnets: null
    Subnets: null
  aws:elasticbeanstalk:application:
    Application Healthcheck URL: /_health_check.html
  aws:elasticbeanstalk:cloudwatch:logs:
    DeleteOnTerminate: 'false'
    RetentionInDays: '7'
    StreamLogs: 'false'
  aws:elasticbeanstalk:container:tomcat:jvmoptions:
    JVM Options: -Duser.timezone="Asia/Tokyo" -Dhttps.protocols=TLSv1.1,TLSv1.2
    XX:MaxPermSize: 128m
    Xms: 512m
    Xmx: 1024m
  aws:elasticbeanstalk:control:
    DefaultSSHPort: '22'
    LaunchTimeout: '0'
    LaunchType: Migration
    RollbackLaunchOnFailure: 'false'
  aws:elasticbeanstalk:environment:
    EnvironmentType: LoadBalanced
    ExternalExtensionsS3Bucket: null
    ExternalExtensionsS3Key: null
    LoadBalancerType: classic
    ServiceRole: null
  aws:elasticbeanstalk:environment:proxy:
    GzipCompression: 'true'
    ProxyServer: apache
  aws:elasticbeanstalk:healthreporting:system:
    ConfigDocument: '{"Version":1,"CloudWatchMetrics":{"Instance":{"CPUIrq":null,"LoadAverage5min":null,"ApplicationRequests5xx":null,"ApplicationRequests4xx":null,"CPUUser":null,"LoadAverage1min":n...
    HealthCheckSuccessThreshold: Ok
    SystemType: basic
  aws:elasticbeanstalk:hostmanager:
    LogPublicationControl: 'false'
  aws:elasticbeanstalk:managedactions:
    ManagedActionsEnabled: 'false'
    PreferredStartTime: null
  aws:elasticbeanstalk:managedactions:platformupdate:
    InstanceRefreshEnabled: 'false'
    UpdateLevel: null
  aws:elasticbeanstalk:monitoring:
    Automatically Terminate Unhealthy Instances: 'true'
  aws:elasticbeanstalk:sns:topics:
    Notification Endpoint: xxx@xxx.com
    Notification Protocol: email
    Notification Topic ARN: arn:aws:sns:ap-northeast-1:xxx:ElasticBeanstalkNotifications-Environment-dev
    Notification Topic Name: null
  aws:elasticbeanstalk:xray:
    XRayEnabled: 'false'
  aws:elb:healthcheck:
    HealthyThreshold: '5'
    Interval: '10'
    Target: HTTP:80/_health_check.html
    Timeout: '5'
    UnhealthyThreshold: '5'
  aws:elb:listener:443:
    InstancePort: '80'
    InstanceProtocol: HTTPS
    ListenerEnabled: 'true'
    ListenerProtocol: HTTPS
    PolicyNames: null
    SSLCertificateId: arn:aws:acm:ap-northeast-1:xxx:certificate/xxx
  aws:elb:listener:80:
    InstancePort: '80'
    InstanceProtocol: HTTP
    ListenerEnabled: 'true'
    ListenerProtocol: HTTP
    PolicyNames: null
    SSLCertificateId: null
  aws:elb:loadbalancer:
    CrossZone: 'false'
    LoadBalancerHTTPPort: '80'
    LoadBalancerHTTPSPort: '443'
    LoadBalancerPortProtocol: HTTP
    LoadBalancerSSLPortProtocol: HTTPS
    SSLCertificateId: arn:aws:acm:ap-northeast-1:xxx:certificate/xxx
    SecurityGroups: sg-xxx
  aws:elb:policies:
    ConnectionDrainingEnabled: 'false'
    ConnectionDrainingTimeout: '20'
    ConnectionSettingIdleTimeout: '60'

トリガーのしきい値例

・MeasureName: CPU利用率
・UpperThreshold: CPU平均利用率 < 90% -> インスタンス増加
・LowerThreshold: CPU平均利用率 > 10% -> インスタンス減少
・Unit: 単位=%
・BreachDuration: 上記が10分継続した場合、Autoscalingが起動
・IgnoreHealthCheck: デプロイ時にHealthCheckは無視する

Rollingを指定したデプロイ時ダウンタイムを発生させない設定例

1. しきい値等変更作業

Autoscalingの設定、インスタンス台数の設定を変更する。
ダウンタイムを避けるためインスタンスを1台追加し、計2台で一時的に稼働させる。

・実行時間: 2分30秒
・ダウンタイム: 無

AWSEBCloudwatchAlarmHigh.aws:autoscaling:trigger:
  UpperThreshold: '90'
AWSEBCloudwatchAlarmLow.aws:autoscaling:trigger:
  BreachDuration: '10'
  LowerThreshold: '10'
  MeasureName: CPUUtilization
  Statistic: Average
  Unit: Percent
aws:autoscaling:asg:
  MaxSize: '4'
  MinSize: '2'
aws:autoscaling:updatepolicy:rollingupdate:
  MaxBatchSize: '2'
  MinInstancesInService: '2'
aws:elasticbeanstalk:command:
  BatchSizeType: Percentage
  IgnoreHealthCheck: 'true'

2. 新しいアプリケーションのデプロイ

2台のインスタンスへ対して、1つずつ順にデプロイされる。
その間、サイトが遅くなる可能性はあるものの、サービスのダウンタイムは発生しない。

・実行時間: 約6分30秒
・ダウンタイム: 無

3. インスタンス数を戻す

デプロイの為に追加したインスタンスの台数を減らす。
実行時間: 約2分

aws:autoscaling:asg:
  MaxSize: '4'
  MinSize: '1'
aws:autoscaling:updatepolicy:rollingupdate:
  MaxBatchSize: '2'
  MinInstancesInService: '2'

参考site

デプロイポリシーと設定
Elastic Beanstalk 環境設定のローリング更新
すべての環境に対する汎用オプション

[AWS][Beanstalk][Shell Script] デプロイスクリプト

AWS Elastic Beanstalk へのデプロイ

殴り書きです。

  • Gitからリポジトリを取得
  • 環境毎に設定を上書き
  • コンパイル
  • EB CLIでデプロイ

シェルスクリプト

sedで環境設定ファイルを書き換えている部分は引数渡しへ変更下さい。

#!/bin/bash
## Example of Beanstalk deploy
##
set -Ceu
PATH=/root/.local/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/opt/aws/bin:/root/bin

# Path
doc_path=/var/www/vhosts/
deploy_path=/var/www/vhosts/xxx
branch=develop

# Beanstalk Environment
prod_env=prod-xxx
stg_env=stg-xxx
dev_env=dev-xxx

# Beanstalk application
prod_app=xxx
stg_app=xxx
dev_app=xxx

# Beanstalk Keyname
prod_key=xxx
stg_key=xxx
dev_key=xxx

# AWS profile
prod_profile=prod
stg_profile=stg
dev_profile=dev

# Domain
prod_domain=xxx.com
stg_domain=xxx.com
dev_domain=xxx.com

# Internal ELB
prod_elb=internal-prod-xxx.com
sgc_elb=internal-stg-xxx.com
dev_elb=internal-dev-xxx.com

# Confirm Git CLI
if ! type 'git' > /dev/null 2>&1; then
  echo 'Git CLI not found.'
  exit 1
fi

cd ${doc_path}

# Confirm Deploy PATH
if [ -e "${deploy_path}" ]; then
  echo 'Remove existing Working copy.'
  rm -rf {woking copy}
fi

git clone https://github.com/xxx.git
cd ${deploy_path}

git checkout ${branch}

cd ${deploy_path}

git status

echo '~~~~~~~~~~~~ Overwrite conf file ~~~~~~~~~~~~'

# 00_application.conf
sed -i -e "s@${prod_elb}@${dev_elb}@g" ./src/main/ebextensions/httpd/conf.d/elasticbeanstalk/00_application.conf

# config.yml
sed -i -e "s@${prod_env}@${dev_env}@g" ./.elasticbeanstalk/config.yml
sed -i -e "s@${stg_env}@${dev_env}@g" ./.elasticbeanstalk/config.yml
sed -i -e "s@application_name: ${prod_app}@application_name: ${dev_app}@g" ./.elasticbeanstalk/config.yml
sed -i -e "s@default_ec2_keyname: ${prod_key}@default_ec2_keyname: ${dev_key}@g" ./.elasticbeanstalk/config.yml
sed -i -e "s@profile: ${prod_profile}@profile: ${dev_profile}@g" ./.elasticbeanstalk/config.yml

# httpd.conf ServerName
sed -i -e "s@${prod_domain}@${dev_domain}@g" ./src/main/ebextensions/httpd/conf/httpd.conf

# 00-basic-setting.config HOSTNAME
sed -i -e "s@${prod_domain}@${dev_domain}@g" ./src/main/ebextensions/00-basic-setting.config

if grep "${prod_elb}" "./src/main/ebextensions/httpd/conf.d/elasticbeanstalk/00_application.conf" >/dev/null; then
  echo 'failed to overwrite in 00_application.conf.'
  exit 1
elif grep "${prod_profile}" "./.elasticbeanstalk/config.yml" >/dev/null; then
  echo 'failed to overwrite in config.yml.'
  exit 1
elif grep "${prod_domain}" "./src/main/ebextensions/httpd/conf/httpd.conf" >/dev/null; then
  echo 'failed to overwrite in httpd.conf.'
  exit 1
else
  echo 'overwrite ok'
fi

echo '~~~~~~~~~~~~ Compile ~~~~~~~~~~~~'
mvn clean package

# Confirm EB CLI
if ! type 'eb' > /dev/null 2>&1; then
  echo 'EB CLI not found...'
  exit 1
fi

echo '~~~~~~~~~~~~ eb status ~~~~~~~~~~~~'
eb status ${dev_env}

echo '~~~~~~~~~~~~ Start deploy ~~~~~~~~~~~~'
eb deploy ${dev_env} --process --timeout 10

sleep 60s

echo '~~~~~~~~~~~~ eb logs ~~~~~~~~~~~~'
eb logs ${dev_env}

echo '~~~~~~~~~~~~ Deployment success ! ~~~~~~~~~~~~'

exit 0

関連記事