├── app ├── site │ ├── css │ │ ├── style.css │ │ └── main.css │ └── index.html ├── Dockerfile └── nginx.conf ├── manifests ├── service.yml └── deployment.yml ├── LICENSE ├── CONTRIBUTING.md ├── .github └── workflows │ └── build.yml ├── README.md └── CODE_OF_CONDUCT.md /app/site/css/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | color: white; 3 | background-color: black; 4 | } 5 | 6 | #content { 7 | background-color: black; 8 | } 9 | -------------------------------------------------------------------------------- /app/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM nginx 2 | 3 | COPY nginx.conf /etc/nginx/conf.d/default.conf 4 | 5 | WORKDIR /usr/share/nginx/html 6 | COPY site . 7 | 8 | CMD sed -i -e 's/$PORT/'"$PORT"'/g' /etc/nginx/conf.d/default.conf && nginx -g 'daemon off;' 9 | -------------------------------------------------------------------------------- /manifests/service.yml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: aws-example-octodex 5 | spec: 6 | type: LoadBalancer 7 | ports: 8 | - port: 80 9 | targetPort: 5000 10 | selector: 11 | app: aws-example-octodex 12 | -------------------------------------------------------------------------------- /app/nginx.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 5000; 3 | server_name localhost; 4 | 5 | location / { 6 | root /usr/share/nginx/html; 7 | index index.html index.htm; 8 | } 9 | 10 | #error_page 404 /404.html; 11 | 12 | # redirect server error pages to the static page /50x.html 13 | # 14 | error_page 500 502 503 504 /50x.html; 15 | location = /50x.html { 16 | root /usr/share/nginx/html; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /manifests/deployment.yml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apps/v1beta1 3 | kind: Deployment 4 | metadata: 5 | name: aws-example-octodex 6 | annotations: 7 | fluxcd.io/automated: "true" 8 | spec: 9 | replicas: 1 10 | strategy: 11 | rollingUpdate: 12 | maxSurge: 1 13 | maxUnavailable: 1 14 | minReadySeconds: 5 15 | template: 16 | metadata: 17 | labels: 18 | app: aws-example-octodex 19 | spec: 20 | containers: 21 | - name: aws-example-octodex 22 | # image: 00000000000000.dkr.ecr.my-region.amazonaws.com/example-eks:tag 23 | image: REGISTRY/IMAGE:TAG 24 | ports: 25 | - containerPort: 5000 26 | resources: 27 | requests: 28 | cpu: 250m 29 | limits: 30 | cpu: 500m 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 GitHub 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Contributing 2 | 3 | [fork]: https://github.com/github-developer/example-actions-flux-eks/fork 4 | [pr]: https://github.com/github-developer/example-actions-flux-eks/compare 5 | [code-of-conduct]: CODE_OF_CONDUCT.md 6 | 7 | Hi there! We're thrilled that you'd like to contribute to this project. Your help is essential for keeping it great. 8 | 9 | Contributions to this project are [released](https://help.github.com/articles/github-terms-of-service/#6-contributions-under-repository-license) to the public under the [MIT License](LICENSE). 10 | 11 | Please note that this project is released with a [Contributor Code of Conduct][code-of-conduct]. By participating in this project you agree to abide by its terms. 12 | 13 | ## Submitting a pull request 14 | 15 | 0. [Fork][fork] and clone the repository 16 | 0. Configure the project as detailed in the [README](README.md). 17 | 0. Make your change 18 | 0. Push to your fork and [submit a pull request][pr] 19 | 0. Pat your self on the back and wait for your pull request to be reviewed and merged. 20 | 21 | Here are a few things you can do that will increase the likelihood of your pull request being accepted: 22 | 23 | - Keep your change as focused as possible. If there are multiple changes you would like to make that are not dependent upon each other, consider submitting them as separate pull requests. 24 | - Write a [good commit message](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html). 25 | 26 | ## Resources 27 | 28 | - [How to Contribute to Open Source](https://opensource.guide/how-to-contribute/) 29 | - [Using Pull Requests](https://help.github.com/articles/about-pull-requests/) 30 | - [GitHub Help](https://help.github.com) 31 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | # build.yml 2 | on: 3 | pull_request: 4 | paths: 5 | - app/** 6 | push: 7 | paths: 8 | - app/** 9 | branches: # array of glob patterns matching against refs/heads. Optional; defaults to all 10 | - master # triggers on pushes that contain changes in master 11 | 12 | name: Build and Push to ECR 13 | 14 | # https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-envvars.html 15 | env: 16 | AWS_DEFAULT_REGION: eu-west-1 17 | AWS_DEFAULT_OUTPUT: json 18 | AWS_ACCOUNT_ID: ${{ secrets.AWS_ACCOUNT_ID }} 19 | AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} 20 | AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} 21 | CONTAINER_IMAGE: example-eks:${{ github.sha }} 22 | 23 | jobs: 24 | build-and-push: 25 | name: Build and deploy 26 | runs-on: ubuntu-latest 27 | steps: 28 | 29 | - name: Checkout 30 | uses: actions/checkout@master 31 | 32 | # Add steps here like linting, testing, minification, etc. 33 | 34 | - name: Setup ECR 35 | run: | 36 | # Login to AWS ECR 37 | $( aws ecr get-login --no-include-email ) 38 | 39 | - name: Build and tag the image 40 | run: | 41 | # Build and tag the image 42 | docker build \ 43 | -t $CONTAINER_IMAGE \ 44 | -t $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$CONTAINER_IMAGE ./app 45 | 46 | # Add additional steps here like scanning of image 47 | 48 | # Only push to registry on master 49 | - name: Push 50 | if: github.ref == 'refs/heads/master' 51 | run: | 52 | # Push image to AWS ECR 53 | docker push $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$CONTAINER_IMAGE 54 | -------------------------------------------------------------------------------- /app/site/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | zen 10 | 11 | 12 | 20 | 21 | 22 | 23 |
24 |         MMM.           .MMM
25 |         MMMMMMMMMMMMMMMMMMM
26 |         MMMMMMMMMMMMMMMMMMM      ____________________________
27 |        MMMMMMMMMMMMMMMMMMMMM    |                            |
28 |       MMMMMMMMMMMMMMMMMMMMMMM   | Keep it logically awesome. |
29 |      MMMMMMMMMMMMMMMMMMMMMMMM   |_   ________________________|
30 |      MMMM::- -:::::::- -::MMMM    |/
31 |       MM~:~ 00~:::::~ 00~:~MM
32 |  .. MMMMM::.00:::+:::.00::MMMMM ..
33 |        .MM::::: ._. :::::MM.
34 |           MMMM;:::::;MMMM
35 |    -MM        MMMMMMM
36 |    ^  M+     MMMMMMMMM
37 |        MMMMMMM MM MM MM
38 |             MM MM MM MM
39 |             MM MM MM MM
40 |          .~~MM~MM~MM~MM~~.
41 |       ~~~~MM:~MM~~~MM~:MM~~~~
42 |      ~~~~~~==~==~~~==~==~~~~~~
43 |       ~~~~~~==~==~==~==~~~~~~
44 |           :~==~==~==~==~~
45 |     
46 | 63 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Example GitHub Actions workflow with Flux and Amazon EKS 2 | 3 | An example workflow that uses [GitHub Actions](https://help.github.com/en/categories/automating-your-workflow-with-github-actions) to build [a static website](app/site/) into a Docker container, push that image to Amazon Elastic Container Registry, and uses [Flux](https://www.weave.works/oss/flux/) to automatically update an existing Amazon Elastic Kubernetes Service cluster with that image. 4 | 5 | See this [technical blog post](https://www.weave.works/blog/gitops-with-github-actions-eks) which uses this code for full step-by-step instructions. 6 | 7 | ## Prerequisites 8 | 9 | 1. Create an EKS cluster, e.g. using [`eksctl create cluster`](https://eksctl.io/) 10 | 2. Set up Flux on the cluster, e.g. using [this guide](https://docs.fluxcd.io/en/1.20.0/get-started). Note that you must set `--git-path` to point to where your manifests are. For example: 11 | ```bash 12 | export GHOWNER= 13 | export GHREPO=example-actions-flux-eks 14 | 15 | kubectl create ns flux 16 | 17 | fluxctl install \ 18 | --git-user=${GHUSER} \ 19 | --git-email=${GHUSER}@users.noreply.github.com \ 20 | --git-url=git@github.com:${GHOWNER}/${GHREPO} \ 21 | --git-path=manifests \ 22 | --namespace=flux | kubectl apply -f - 23 | ``` 24 | 3. Give Flux read/write access to the GitHub repository [using a deploy key](https://docs.fluxcd.io/en/1.20.0/tutorials/get-started/#giving-write-access) 25 | 4. Create a repository called `example-eks` in [Amazon Elastic Container Registry](https://docs.aws.amazon.com/AmazonECR/latest/userguide/Registries.html), in the same AWS region as the EKS cluster 26 | 5. Update the image in [`deployment.yml`](manifests/deployment.yml) to use your `REGISTRY`, `IMAGE`, and `TAG`. `TAG` will be replaced by Flux as new images are available in the registry. 27 | 28 | ## Secrets 29 | 30 | The following secrets are required to be set on the repository: 31 | 32 | 1. `AWS_ACCOUNT_ID`: The AWS account ID that owns the EKS cluster 33 | 1. `AWS_ACCESS_KEY_ID`: An AWS access key ID for an account having the [EKS IAM role](https://docs.aws.amazon.com/eks/latest/userguide/service_IAM_role.html) 34 | 1. `AWS_SECRET_ACCESS_KEY`: An AWS secret sccess key for an account having the [EKS IAM role](https://docs.aws.amazon.com/eks/latest/userguide/service_IAM_role.html) 35 | 36 | ## Workflow 37 | 38 | The [example workflow](.github/workflows/build.yml) will trigger on every push to this repo. 39 | 40 | For _pull requests_, the workflow will: 41 | 1. Build and tag [the Docker image](app/Dockerfile) 42 | - The image will be tagged with the feature branch's HEAD commit SHA 43 | 44 | For _pushes_ to the default branch (`master`), in addition to the above, the workflow will: 45 | 46 | 1. Push the image to Amazon Elastic Container Registry 47 | 48 | ## Beyond the workflow 49 | 50 | Flux watches ECR for changes to the image listed in our [deployment configuration](manifests/deployment.yml). When it detects a change, it updates the EKS cluster with the new image, no manual `kubectl apply` needed! 51 | 52 | ## Contributions 53 | 54 | We welcome contributions! See [how to contribute](CONTRIBUTING.md). 55 | 56 | ## License 57 | 58 | [MIT](LICENSE) 59 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to make participation in our project and our 7 | community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and 9 | expression, level of experience, education, socio-economic status, nationality, 10 | personal appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | - Using welcoming and inclusive language 18 | - Being respectful of differing viewpoints and experiences 19 | - Gracefully accepting constructive criticism 20 | - Focusing on what is best for the community 21 | - Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | - The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | - Trolling, insulting/derogatory comments, and personal or political attacks 28 | - Public or private harassment 29 | - Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | - Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or reject 41 | comments, commits, code, wiki edits, issues, and other contributions that are 42 | not aligned to this Code of Conduct, or to ban temporarily or permanently any 43 | contributor for other behaviors that they deem inappropriate, threatening, 44 | offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies within all project spaces, and it also applies when 49 | an individual is representing the project or its community in public spaces. 50 | Examples of representing a project or community include using an official 51 | project e-mail address, posting via an official social media account, or acting 52 | as an appointed representative at an online or offline event. Representation of 53 | a project may be further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at 59 | opensource+github-developer/example-actions-flux-eks@github.com. All complaints will be reviewed 60 | and investigated and will result in a response that is deemed necessary and 61 | appropriate to the circumstances. The project team is obligated to maintain 62 | confidentiality with regard to the reporter of an incident. Further details of 63 | specific enforcement policies may be posted separately. 64 | 65 | Project maintainers who do not follow or enforce the Code of Conduct in good 66 | faith may face temporary or permanent repercussions as determined by other 67 | members of the project's leadership. 68 | 69 | ## Attribution 70 | 71 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 72 | version 1.4, available at 73 | https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 74 | 75 | [homepage]: https://www.contributor-covenant.org 76 | 77 | For answers to common questions about this code of conduct, see 78 | https://www.contributor-covenant.org/faq 79 | -------------------------------------------------------------------------------- /app/site/css/main.css: -------------------------------------------------------------------------------- 1 | /*! normalize.css v2.1.3 | MIT License | git.io/normalize */@import url(//fonts.googleapis.com/css?family=Inconsolata:400,700|Montserrat:700);article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,video{display:inline-block}audio:not([controls]){display:none;height:0}[hidden],template{display:none}html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}a{background:transparent}a:focus{outline:thin dotted}a:active,a:hover{outline:0}h1{font-size:2em;margin:0.67em 0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}dfn{font-style:italic}hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0}mark{background:#ff0;color:#000}code,kbd,pre,samp{font-family:monospace, serif;font-size:1em}pre{white-space:pre-wrap}q{quotes:"\201C" "\201D" "\2018" "\2019"}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:0}fieldset{border:1px solid #c0c0c0;margin:0 2px;padding:0.35em 0.625em 0.75em}legend{border:0;padding:0}button,input,select,textarea{font-family:inherit;font-size:100%;margin:0}button,input{line-height:normal}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0}input[type="search"]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}textarea{overflow:auto;vertical-align:top}table{border-collapse:collapse;border-spacing:0}html{font:16px/1.5 Inconsolata, sans-serif}@media (min-width: 30rem){html{font-size:20px}}body{margin:2rem 0 5rem;color:#333}@media (min-width: 30rem){body{margin-top:5rem}}a{color:#0074d9;text-decoration:none}a:hover,a:focus{text-decoration:underline}h1,h2,h3,h4,h5,h6{font-family:Montserrat, sans-serif;margin:0 0 0.5rem -0.1rem;line-height:1;color:#111;text-rendering:optimizeLegibility}h1{font-size:2.5rem;margin-bottom:1rem}@media (min-width: 30rem){h1{font-size:3rem;margin-bottom:3rem}}h1 a{color:inherit}h2{margin-top:2rem;font-size:1.25rem;margin-bottom:0.75rem}@media (min-width: 30rem){h2{margin-top:2.5rem;font-size:1.5rem;margin-bottom:1rem}}h3,h4,h5,h6{margin-top:1.5rem;font-size:1rem;text-transform:uppercase}p,ul,ol,dl,table,pre,blockquote{margin-top:0;margin-bottom:1rem}ul,ol{padding-left:1.5rem}dd{margin-left:1.5rem}blockquote{margin-left:0;margin-right:0;padding:.5rem 1rem;border-left:.25rem solid #ccc;color:#666}blockquote p:last-child{margin-bottom:0}hr{border:none;margin:1.5rem 0;border-bottom:1px solid #ccc;position:relative;top:-1px}.container img,.container iframe{max-width:100%}.container img{margin:0 auto;display:block}table{width:100%;border:1px solid #ccc;border-collapse:collapse}td,th{padding:.25rem .5rem;border:1px solid #ccc}pre,code{font-family:inherit;background-color:#eee}pre{padding:.5rem 1rem;font-size:0.8rem}code{padding:.1rem .25rem}pre>code{padding:0}.container{max-width:30rem;margin:0 auto;padding:0 1rem}.hll{background-color:#ffc}.c{color:#999}.err{color:#AA0000;background-color:#faa}.k{color:#006699}.o{color:#555}.cm{color:#0099FF;font-style:italic}.cp{color:#099}.c1{color:#999}.cs{color:#999}.gd{background-color:#FFCCCC;border:1px solid #c00}.ge{font-style:italic}.gr{color:red}.gh{color:#003300}.gi{background-color:#CCFFCC;border:1px solid #0c0}.go{color:#aaa}.gp{color:#000099}.gu{color:#003300}.gt{color:#9c6}.kc{color:#006699}.kd{color:#006699}.kn{color:#006699}.kp{color:#069}.kr{color:#006699}.kt{color:#007788}.m{color:#f60}.s{color:#d44950}.na{color:#4f9fcf}.nb{color:#366}.nc{color:#00AA88}.no{color:#360}.nd{color:#99f}.ni{color:#999999}.ne{color:#CC0000}.nf{color:#c0f}.nl{color:#99f}.nn{color:#00CCFF}.nt{color:#2f6f9f}.nv{color:#033}.ow{color:#000000}.w{color:#bbb}.mf{color:#f60}.mh{color:#f60}.mi{color:#f60}.mo{color:#f60}.sb{color:#c30}.sc{color:#c30}.sd{color:#CC3300;font-style:italic}.s2{color:#c30}.se{color:#CC3300}.sh{color:#c30}.si{color:#a00}.sx{color:#c30}.sr{color:#3aa}.s1{color:#c30}.ss{color:#fc3}.bp{color:#366}.vc{color:#033}.vg{color:#033}.vi{color:#033}.il{color:#f60}.css .o,.css .o+.nt,.css .nt+.nt{color:#999} --------------------------------------------------------------------------------