みなさんこんにちは! Habréでは、 ConcourseCIなどのアセンブリサーバーに関する情報がほとんどないことに気付きました。 このギャップを埋めて簡単な紹介文を書くことにしました。 このツールの猫の説明と小さなチュートリアルの下。
したがって、ConcourseCIはCI / CDビルドサーバーです。 Pivotalによって開発されており、現在活発に開発されています。 会社自体にはこのプロジェクトにフルタイムで取り組んでいる人が何人かいるため、現在、新しいバージョンがかなり定期的にリリースされており、追加機能が積極的に実装され、バグが迅速に修正されています。 当初、最も頻繁に起こるように、PivotalはJenkinsに不満だったため、このツールを社内で使用するために作成しましたが、後にこのプロジェクトをGithubに公開し、コミュニティが引き継いだため、リリースはしばしばコミュニティのサードパーティ開発者からの新しい機能を思い付きます。 完全にGoで書かれています。
この記事では:
長所
この製品の主な利点をリストします。
- 各操作は個別のDockerコンテナーで起動されるため、この製品はテクノロジーに完全に依存しません。 つまり、任意のdockerコンテナー内で収集された任意のコードを収集できます
- 組み立てプロセスは、いわゆる パイプライン 、現代のアセンブリはますます線形になってきているため。 そして、このようなスケジュールの形で複雑な組み立て手順を説明することは、非常に便利で明確になります。 ConcourseCIには、読み取り専用の使いやすいグラフィカルWebインターフェイスが付属しています。
新しいデザインは現在ベータモードですが、コミュニティによって活発に議論されているため、私のスクリーンショットは近い将来に時代遅れになる可能性があります。 新しいインターフェイスは次のようになります。
- 箱から出して簡単に水平に伸びます。 十分なリソースがない場合は、新しいマシンで別のワーカーを起動し、メインサーバーのアドレスをパラメーターとして指定すると、他のすべてが自動的に行われます:ワーカーは自分自身を登録し、自分自身について通知し、すぐにいくつかの作業を行う準備ができます。 。 さらに、アセンブリプロセス中に並列操作がある場合は、異なる物理マシンで実行される可能性があります。 新しいワーカーを追加する操作は、文字通り1つのコマンドを起動することです。
設置
前述したように、プロジェクトはGoで記述されているため、このリリースには単一のバイナリファイルが付属しており、1つのコマンドで実行できます。 しかし、より良い方法があります。 ConcourseCIは公式のdocker imageを提供するため、docker-composeを使用して、1つのチームだけでプロジェクトを開始できます。
開始されたConcourseCIは、3つの部分で構成されています。
- PostgreSQLデータベース
- コンコースWeb 。 これは一種のマスターです。 グラフィカルWebインターフェイスと、最も重要なことは、航空から借用した ATC ( 「ATC」または「航空交通管制」という用語:これは、管制官がフライトを監視する滑走路近くの空港にあるフライトコントロールタワーです)。 ATCはリソースを割り当て、さまざまなタスクを実行し、クラスターを監視します。 実際のアセンブリはConcourse Webでは発生せず、アセンブリを管理するだけで、アクセス可能なワーカーにタスクを委任することに注意してください。 メインのConcourse Webシステムは1つだけ存在できます。
- コンコースワーカー -ここで実際の作業が行われます。 ワーカーは、ATCからタスクを受け取り、それを実行して、結果を報告します。 システムには、十分な鉄があるのと同じ数のそのようなワーカーが存在する可能性があります。 1つのサーバー/インスタンスで1つのワーカーを実行することをお勧めします。
したがって、完全に機能するサーバーは、1つのdocker-composeコマンドで起動できます。 ただし、ATCは暗号化されたチャネルを介してワーカーと通信し、開始する前に両側でキーをスリップする必要があるため、最初の開始前にキーを生成する必要があります。 次のようなキーを生成します。
mkdir -p keys/web keys/worker ssh-keygen -t rsa -f ./keys/web/tsa_host_key -N '' ssh-keygen -t rsa -f ./keys/web/session_signing_key -N '' ssh-keygen -t rsa -f ./keys/worker/worker_key -N '' cp ./keys/worker/worker_key.pub ./keys/web/authorized_worker_keys cp ./keys/web/tsa_host_key.pub ./keys/worker
その後、このファイルを使用してシステム全体を起動できます(公式ファイルはこちらを参照 )。
version: '3' services: concourse-db: image: postgres:9.6 environment: POSTGRES_DB: concourse POSTGRES_USER: concourse POSTGRES_PASSWORD: changeme PGDATA: /database concourse-web: image: concourse/concourse links: [concourse-db] command: web depends_on: [concourse-db] ports: ["8080:8080"] volumes: ["./keys/web:/concourse-keys"] restart: unless-stopped # required so that it retries until concourse-db comes up environment: CONCOURSE_BASIC_AUTH_USERNAME: concourse CONCOURSE_BASIC_AUTH_PASSWORD: changeme CONCOURSE_EXTERNAL_URL: "${CONCOURSE_EXTERNAL_URL}" CONCOURSE_POSTGRES_HOST: concourse-db CONCOURSE_POSTGRES_USER: concourse CONCOURSE_POSTGRES_PASSWORD: changeme CONCOURSE_POSTGRES_DATABASE: concourse concourse-worker: image: concourse/concourse privileged: true links: [concourse-web] depends_on: [concourse-web] command: worker volumes: ["./keys/worker:/concourse-keys"] environment: - CONCOURSE_TSA_HOST=concourse-web:2222
Webインターフェイスを使用できるWebアドレスの実際の値を変数CONCOURSE_EXTERNAL_URL
にエクスポートすることを忘れないでください。
export CONCOURSE_EXTERNAL_URL=http://192.168.99.100:8080
ご覧のとおり、この例ではすべてを1台のマシンで実行していますが、誰もこれに制限するものではなく、ニーズに応じて分散クラスターを安全に作成できます。
起動後、ブラウザでサーバーアドレスを開くことができ(上記の例-http://192.168.99.100:8080 )、まだ空のConcourse Webが表示されます。
インストールの詳細については、 こちらをご覧ください 。
3つのコンセプト
ですから、ビジネスに取りかかる前に、お互いを理解するために用語を見てみましょう。 ConcourseCIは3つの基本概念で動作します。
リソース -アセンブリの材料を提供できるリソース、またはアセンブリの結果によって更新できるリソース。 典型的な例:git / hgリポジトリ、docker-register、FTP、S3、チャット、電子メール、電報ボットなど。 完全なリストはこちらです 。さらに、Githubの広大さでいつでも何かを見つけることができ、極端な場合は自分で書くことができます 。 リソースは特定の作業を行わず、さらなるアクションのために資料を「提供する」だけであることを理解することが重要です。
タスクは、ビルドの一部として実行できる作業単位です。 タスクは、選択したdockerコンテナーで起動されます。
- ジョブ -タスク。 リソースとタスクを1つに結合します。 つまり、割り当て内でリソースを取得し、何らかの形でタスクで処理し、リソースを収集して結果を更新します。 1つのタスクは完全に分離されており、何度でも別々に実行できます。
Webインターフェイスの外観
そして、ブラウザーではConcourseCIは次のようになります。
これはパイプラインの非常に単純な例ですが、ここではGitリポジトリからソースを取得してプロジェクトの構築を開始し、ドッカーイメージを作成し、適切なリソースを使用して電報チャネルの全員に通知する方法を見ることができます。
このスクリーンショットでは、リソースとタスクのみが表示されますが、タスクは表示されません。 ただし、タスクの1つ(この例では1つ)をクリックすると、緑色の四角酸塩の内部で何が起こっているかを確認できます。
この図では、数字にマークが付けられています。
- 手動でタスクを開始するボタン。 いつでも再実行できます
- 以前のすべてのビルドは、履歴の形式で見出しの下に長いチェーンで配置されます
- ソースを取得するリソース。 下矢印は「取得」を意味します。つまり、リソースから素材を「取得」します。
- 1つのタスクの作業の終了。 このリンクを開いて、プロジェクトのアセンブリ中に発生したコンテナのstdoutログを確認できます。
- リソース(dockerイメージ)を収集し、プライベートレジスタにドロップします。 上矢印はプットを意味します。つまり、リソースを更新しています
- 最後に、私達は私用電報チャネルでメッセージを投げます
このインターフェイスでは、すべてのパイプラインとタスクを表示し、結果を監視できます。
コンベヤーの完全に「高度な」バージョンの例として、 ConcourseCI自体のコンベヤーを引用できます (はい、驚くべきことに、彼自身がそれを自分で組み立てるつもりです:))
しかし、前述したように、ここのWebは読み取り専用です。 合理的な疑問が生じます。新しいコンベアをプロジェクトに追加する方法は? 飛ぶことを紹介する時です。
飛ぶ
Flyは、ターミナルからConcourseCIクラスター全体を管理できるコマンドラインユーティリティです。 稼働中のコンピューターにインストールされ、サーバーを管理します。 これにより、必要なすべての操作を実行し、クラスターを維持できます。
このコマンドのヘルプ出力(小さな部分):
$ fly help Usage: fly [OPTIONS] <command> Application Options: -t, --target= Concourse target name -v, --version Print the version of Fly and exit --verbose Print API requests and responses --print-table-headers Print table headers even for redirected output Help Options: -h, --help Show this help message Available commands: abort-build Abort a build (aliases: ab) builds List builds data (aliases: bs) check-resource Check a resource (aliases: cr) checklist Print a Checkfile of the given pipeline (aliases: cl) containers Print the active containers (aliases: cs) destroy-pipeline Destroy a pipeline (aliases: dp) destroy-team Destroy a team and delete all of its data (aliases: dt) execute Execute a one-off build using local bits (aliases: e) ..... ..
チームはGoで記述された1つのバイナリでもあります。 githubからダウンロードできますが、Webインターフェースの下部にあるリンクを使用してダウンロードする方が便利です。
/usr/bin/fly
にドロップして実行します。
これで、flyがインストールされました。 ConcourseCIを開始するには、サーバーに対して認証する必要があります。 これは非常に簡単に行われます:
$ fly --target office login --concourse-url=http://ci.your.concouce.server.com
どこで:
- --target (または-t )このサーバー(ターゲット、ターゲットサーバー)の名前を指定します。 この例では、これは「office」という名前です。 実際には、複数のサーバーを使用できます。1つは会社用、1つはチーム専用、もう1つはローカルコンピューター上にあり、チュートリアルのトレーニングを行います。 -tオプションを使用すると、これらのサーバーを簡単に切り替えることができます。
- login-ログインコマンド
- --concourse-url -ConcourseCIクラスターが配置されているURLを指定します 。 初めて示される。
コマンドを入力すると、ユーザー名とパスワードの入力を求められます。 インストール中にdocker-compose.ymlファイルで指定したデータを入力します( CONCOURSE_BASIC_AUTH_USERNAME
およびCONCOURSE_BASIC_AUTH_PASSWORD
、上記を参照)
$ fly help
またはドキュメントページで入力すると、使用可能なすべてのコマンドのリストを見つけることができます 。
ログインに成功すると、すでに作業を開始できます。 このコマンドで最初のパイプラインを作成できるとしましょう:
$ fly -t office sp -c pipeline.yml -p my-pipeline-name
ここで:
- -t office-コマンドを実行するターゲットサーバーを示します(この例では、前の手順でログイン時に作成したoffice )
- sp (またはset-pipeline )-直接、新しいパイプラインを作成するコマンド。 各チームには独自の短いエイリアスがあります。 完全な
set-pipeline
コマンドを書くか、短いsp
エイリアスを使用できます-結果は同じになります - -c pipeline.yml-パイプライン自体の設定を含むファイル。YAMLマークアップ言語で記述されています。 次の章はこれに専念します。
- -p my-pipeline-name -Webインターフェースに表示されるこのパイプラインの名前を設定します。
このコマンドを実行した後、ブラウザーでConcourseCIを開き、新しいパイプラインを確認できます。 最初は一時停止されます。 新しいパイプラインをアクティブにするには、ブラウザの青い「▸」ボタンをクリックします
またはチームを使用する
$ fly -t office unpause-pipeline -p my-pipeline-name
パイプライン構成
パイプラインの記述がどのように進行しているかを検討する時が来ました。 ファイルはYAML形式で記述され、プロジェクトのソースと同じリポジトリに、つまりコードに「近い」ように保存できます。 言い換えれば、各プロジェクトは「自分自身を組み立てる方法を知っている」と言うことができます。これは、構成がその中にあるためです。 これは非常に便利です。各プログラマーは完全なアセンブリの詳細と微妙さを確認できるため、開発に役立つことは間違いありません。
ファイルは、リソースの宣言(リソース)とタスクの説明(ジョブ)のいくつかの部分に分割できます。 たとえば、Javaプロジェクトの単純なパイプラインを作成しましょう。 この場合、Gitリポジトリからソースを取得し、Gradleを使用してテストを実行してプロジェクトをビルドし、ビルド結果をAmazon S3クラウドにドロップします。
リソースから始めましょう。 それらはリソースのセクションで説明されています。 この場合、GitリポジトリとAWS S3の2つのリソースを宣言する必要があります。
resources: - name: source-code type: git source: uri: git@your-project.git branch: master private_key: | ......... - name: aws-s3-release type: s3 source: bucket: releases regexp: directory_on_s3/release-(.*).tgz access_key_id: ........ secret_access_key: ........
任意の名前(-name)を付けます。これにより、これらのリソースにアクセスし、同じ名前でブラウザーにリソースが表示されます。
次に、3つのことを行う1つのジョブを作成します。
- 宣言された
source-code
リソースからsource-code
- プロジェクトを集める
-
aws-s3-release
デプロイする
タスクについては、 jobs
セクションで説明しています。好きなだけ作成できます。 簡単な例では、「プロジェクトのビルド」という名前のタスクを1つだけ実行しています。
jobs: - name: "Build project" plan: # - get: source-code trigger: true # , # - task: "Build gradle project" config: platform: linux image_resource: type: docker-image source: {repository: "chickenzord/alpine-gradle", tag: "latest" } inputs: - name: source-code outputs: - name: result-jar run: path: sh args: - -exc - | cd source-code gradle test gradle build # output, # cp build/libs/app.jar ../result-jar # S3 - put: aws-s3-release params: file: result-jar/app.jar acl: public-read
この例をさらに詳しく見ていきましょう。
リソースのすべては明確です。それを-getとして宣言し- get
。これは、データを取得することを意味します。 trigger: true
パラメーターは、リソースが更新されるたびにタスク自体が起動されることを意味します(この場合、誰かがコミットし、コミットを開始したことを意味します)。 必要に応じて、より具体的なパラメーターを指定できます。これは、正しいリソースのドキュメントに記載されています 。
タスク(タスク)。 ご存知のように、ここで実際のアクションが行われます。 タスクには、留意すべき2つのプロパティがあります。
- 受信および送信データ( 入力および出力 )を持つことができます
- Dockerコンテナーで開始します(実際には、すべてがコンテナーで開始されますが、タスクでは明示的にイメージを指定する必要があります)。
この例では、1つの入力ソースのみを指定しました。
inputs: - name: source-code
受信ソースは、リソースまたは以前に起動された別のタスクのいずれかです(たとえば、チェーンでタスクを実行し、中間結果を次のタスクに渡すことができます)。 実際には、これはコンテナー内に同じ名前のフォルダーがあり、ConcourseCIがこのフォルダー内にリソースのコンテンツ(この場合はgitリポジトリーのコンテンツ)をきちんと配置することを意味します。 そのため、タスクの本文で最初に行ったことは、このフォルダー( cd source-code
)に移動することでした。ここで、Javaプロジェクトのソースコードを取得します。
また、アセンブリに使用するdockerイメージを指定する必要があります。 ここでのロジックは非常に単純です。特定のプロジェクト用のすべてのビルドツールがあるコンテナが必要です。 私の場合、Javaのプロジェクトはgreadによってアセンブルされるため、コンテナー内には必要なバージョンのJavaとgread自体が必要だと言えます。 たとえば、 この画像は機能し、私のタスクに最適です。 このイメージを次のように構成で指定します。
config: platform: linux image_resource: type: docker-image source: {repository: "chickenzord/alpine-gradle", tag: "latest" }
このコンテナ内で、Gredlのタスクを起動できます。これはデモとして行います。
cd source-code gradle test gradle build
はい、ビルド環境に非常に特定の要件がある場合、独自のドッカーイメージを収集してプライベートレジスタに保存することは難しくありません。ConcourseCIはどこからでも簡単にイメージをアップロードできます。
この例では、1つのYAMLファイルで可能な限り明確になるようにすべてを十分に詳細に説明したことにも注意してください。 ただし、タスクは別のYAMLファイルに移動できます 。 異なるプロジェクトでタスクを再利用するのはとても便利です。 この場合、タスクは2行のみで宣言されますが、その「本文」は個別に保存されます。
- task: hello-world file: path/to/my_task.yml
runコマンドにも同じことが当てはまります。その内容はシェルスクリプトに入れて1つのコマンドで参照できるため、コードが短くなります。 たとえば、スクリプトをローカルでテストしたり、 単体テストでカバーしたい場合に便利です。 この場合、タスクは次のようになります。
- task: "Run altogether" config: platform: linux image_resource: type: docker-image source: repository: somedocker/image tag: latest run: path: path/to/script.sh
スクリプトが標準のUNIX 出力結果を返すことを忘れないでください(0-すべてが正常であり、他の数値はエラーです)。 この方法でのみ、ConcourseCIはあなたのチームが成功したかどうかを知ることができます。
最後に、2番目のリソースについて簡単に説明します。これを-put:と宣言します。これは、ソースコードの場合のように、それからデータを取得しないことを意味します。
設定ファイルの準備ができたら、任意の名前(たとえば、 pipeline.yml
でファイルに保存し、次のコマンドでリモートConcourseCIサーバー上でパイプラインを作成/更新する必要があります。
$ fly -t office sp -c pipeline.yml -p my-pipeline-name
その後、ブラウザを開いて、作成(または更新)されたパイプラインを確認します。 gitリポジトリにコミットすると、自動的に開始されます:
この大きな正方形(「プロジェクトのビルド」ジョブ)をクリックすると、詳細が表示されます。 画面上のこれらのステップはすべて「展開」して、コンソールの出力を表示できます。
秘密
私の例では、コード内で直接秘密(パスワード、キー)を保護していることがわかりました。 もちろん、実際のプロジェクトでは、セキュリティ上の考慮事項を考慮する価値はありません。YAMLファイルは一般的なリポジトリにあるからです。 すべての秘密は別々に保管する必要があります。 コンコースでは、パイプラインの更新時にのみ実際の値に置き換えられる特別なエイリアスを使用できます。 パスワードと秘密鍵を二重角括弧で囲まれたプレースホルダーに置き換えたとしましょう:
- name: source-code type: git source: uri: git@your-project.git branch: master private_key: ((git-pivate-key)) - name: aws-s3-release type: s3 source: bucket: releases regexp: directory_on_s3/release-(.*).tgz access_key_id: ((aws-access-key)) secret_access_key: ((aws-secret-key))
そして、すべての値を含むYAML形式のパスワードとキー(たとえば、 credentials-ci.yml
)を使用して、ローカルファイル(コンピューターまたは他の安全なストレージにのみ安全に保存されます)を作成します。
aws-access-key: "myawsaccesskey" aws-secret-key: "myawssecretkey" ftp-password: "my-secure-password" git-pivate-key: | -----BEGIN RSA PRIVATE KEY----- ............
そして、今度は--load-vars-from
オプションを使用して、 --load-vars-from
実際の値に置き換える必要があります。 したがって、完全なパイプラインの作成/更新コマンドは次のようになります。
fly -t office sp -c pipeline.yml -p my-pipeline-name --load-vars-from ~/credentials-ci.yml
これで、パイプラインは共通のリポジトリに保存され、パスワードは安全な場所にある管理者のコンピューターにのみ保存されます。 これで、少なくともパブリックgithubにビルドコンフィギュレーターを安全に残すことができます。
または、 標準のVaultツールのリソースを使用できます 。
なぜタスクが必要なのですか?
おそらく、私の例を見ると、なぜジョブとタスクが必要で、なぜそれらを単一の全体に結合できないのか疑問に思っています(たとえば、これはGitLabCIで行われます )。 1つのタスクを小さなステップに分割する必要があるのはなぜですか? 良い質問です。例を挙げて説明します。
設計上、 ジョブは分離されたタスクであり、コンベアの他の部分に依存しません。 これは、いつでも起動できることを意味し、事前のアクションは必要ありません。 すべての中間および最終操作は内部で行われ、外部ではすべてが単一のステップのように見えます。 したがって、アセンブリ内に個別に存在できない操作がある場合、すべての依存ステップを1つのタスクに結合する必要があります。 これは、一方では困難になります。1つのタスクに集中しすぎるジェスチャが多すぎるため、もう一方には、プロセスを論理的なステップに分割する優れたツールがあります。タスクです。 さらに、各タスクは異なるツールを使用できます。
より明確にするために、より複雑な例を考えてみましょう。 前の段落で、たった1つのチーム( gradle build
組み立てられた単純なプロジェクトの例を挙げました。 しかし、これは常に起こるとは限りません。 古典的なモノリスの例を見てみましょう。フロントエンド、バックエンド、すべてすべてが同じリポジトリにある単一のプロジェクトです。 そのようなプロジェクトの組み立てはどうですか? すべての仮想ステップをリストします。
フロントエンドを収集する必要があります。 スタイルsass / lessなどのプリプロセッサを用意します。 JSファイルを最適化および縮小することもできます。 プロジェクトの顔を収集するために、
npm install
コマンドを使用して依存関係をダウンロードし、その後、gulp
/grunt
などのビルドツールを使用して、既製のコードgrunt
生成します。 それはかなり標準です。 ビルド後、CSSおよびJSコードが最適化および最小化されて完全にコンパイルされる特定のdist
フォルダーを取得します。
( このステップはデモンストレーション目的で追加され、より面白くなりました )現在のリリースに関する情報をアセンブリ段階でコードに直接「埋め込み」たい場合があります。これにより 、現在どのバージョンが実稼働で実行されているかを簡単に判断できます。 サイトの地下にあるページの下部にある小さなレコード
build version 0.11.34.1122
であるか、Gitでの現在のコミットに関するメタ情報(ハッシュ、作成者名、日付など)であり、URLでJSONとして利用できます/version
sayと言う。 このようなオプションは多数あります。 これは、チームが継続的デリバリーのプラクティスを使用し、非常に頻繁にリリースを行う場合に非常に重要です。 これを行うには、Gitからメタ情報を取得して、ある種の構成ファイルに緊密に「縫い付ける」か、HTMLテンプレートに直接「簡単に」縫い付ける小さなスクリプトを作成します。 ( ちなみに、Goでは、コンパイル中に-ldflags
フラグを使用して同じ目標を達成できますが、このステップは例えば別のタスクに意図的に残しました )
- そしてもちろん、サーバー側のアセンブリ。 これを行うには、依存関係をダウンロードし、前の手順で生成されたファイルを転送して、すべてをまとめて収集する必要があります。 今回は、Goでプロジェクトをまとめましょう。 この言語では、さまざまなパッケージマネージャーの動物園全体で、例としてベンダーを取り上げましたが、その本質は変わりません。 アセンブルする前に、
govendor fetch -v +out
コマンドを作成します。これは、ソースの形ですべての新しい依存関係をダウンロードし、vendor
フォルダーに配置します(いくつかのプログラマーは、依存関係を何度もアンロードしないためにフォルダー全体をgitにコミットすることに注意してください;両方のアプローチには長所と短所があり、その議論はこの記事の範囲を超えています)。 さて、依存関係のソースがローカルであることが判明した後、すべてをコンパイルできます。
それで、私たちは何を数えますか?フルビルドを行うには、システムにnpm、gulp、git(sshに依存する)、go、govendorが必要です。覚えているように、ConcourseCIのアセンブリはdockerコンテナで実行されるため、ロジックは、カスタムdockerイメージを構築し、上記のすべてをそこに入れて、プライベートレジスタに配置するのが良いことを示しています。このイメージには必要なものがすべて含まれており、その中に必要なコマンドを実行できます-git、npm、およびgo はい、この方法は機能しますが、もちろんそうする価値はありません。そして、ここでは、1つのタスク(ジョブ)をさまざまな小さなドッカーコンテナーで起動される多くのサブタスクに分割すると便利です。そのため、次のようなタスクがあります。
- NPM依存関係をロードし、クライアント側を構築します。
- Git
- Go
, , . (job), -, .
, , . — NPM, Gulp , — git ssh , — go-vendor . , , , !
, , ? ! ConcourseCI aggregate , , , . , , , , , :
╭ NPM , Gulp build 1. ┨ Git version ╰ Go 2. go build
, ( source-code docker-example-image ):
... jobs: - name: "Build monolith example" plan: - get: source-code trigger: true # aggregate, # - aggregate: # Build the frontend (SASS and Javascript) - task: "Build frontend, compile SASS, download dependencies" config: platform: linux image_resource: type: docker-image source: repository: 'monostream/nodejs-gulp-bower' inputs: - name: source-code outputs: - name: compiled-assets run: path: sh args: - -ec - | cd source-code/ # npm install # gulp build # outputs, # cp -r dist/* ../compiled-assets/ - task: "Download GO dependencies" config: platform: linux image_resource: type: docker-image source: repository: "electrotumbao/go-govendor" inputs: - name: source-code # Go: # # # # path path: src/authorName/repoName outputs: - name: vendor-output run: path: sh args: - -ec - | export GOPATH GOPATH="$(pwd)" cd src/authorName/repoName/ || exit # output, # govendor fetch -v +out cp -r vendor/* "$GOPATH"/vendor-output - task: "Update GIT commit details" config: platform: linux image_resource: type: docker-image source: { repository: 'alpine/git', tag: "latest"} inputs: - name: source-code outputs: - name: versioned-file run: path: sh args: - -ec - | # cd source-code GITSHA=$(git rev-parse HEAD) GITAUTHOR=$(git log --format='%an %ae' -1) GITDATE=$(git log --format='%aD' -1) TODAY=$(date) # - , # sed sed ... # output, # cp version.config ../versioned-file/ # , # , - task: "Build Source Code" config: platform: linux image_resource: type: docker-image source: {repository: "golang", tag: "alpine" } # inputs # inputs: - name: source-code path: src/authorName/repoName - name: versioned-file - name: compiled-assets - name: vendor-output outputs: - name: output-for-docker run: path: sh args: - -ec - | set -e export GOPATH GOPATH="$(pwd)" cd src/daxi.re/cyprus-tours/ || exit # cp -r "$GOPATH"/compiled-assets/* ./assets/ cp -r "$GOPATH"/vendor-output/* ./vendor # go test # , CGO_ENABLED=0 GOOS=linux go build -a -o app . # - # . # , -. # # docker-example-image (. ) # output cp app "$GOPATH"/output-for-docker/ cp Dockerfile "$GOPATH"/output-for-docker/ # , , # - # , # # Dockerfile # ( ) - put: docker-example-image params: { build: output-for-docker } get_params: {rootfs: true}
, .
, , (job). , . , : NPM , — Go ( ). .
, , :
出来上がり! , ! . , -.
, . . , ! !
: