diff --git a/devops/01 - git/README.md b/devops/01 - git/README.md index 1fc3f573..8420bbc5 100644 --- a/devops/01 - git/README.md +++ b/devops/01 - git/README.md @@ -13,16 +13,21 @@ ## Questions -1. What command can I use to view the commit history? +1. What command can I use to view the commit history? `git log` command -1. What command can I use to undo the last commit? +1. What command can I use to undo the last commit? the `git reset` command with the `–soft` option that will preserve changes done to your files -1. What command can I use to create a new branch and a new tag? +1. What command can I use to create a new branch and a new tag? `git branch ; git tag ` -1. How do I exclude a file / folder from a commit? +1. How do I exclude a file / folder from a commit? in `.gitignore`, add the relative path to the file -1. In case of a merge conflict, what commands can be used to resolve it? +1. In case of a merge conflict, what commands can be used to resolve it?
+- `git log --merge` to check the the list of conflicting commits
+- `git reset --mixed` reset can be used to undo changes
+- `git merge --abort` it will exit from the merge process and return the branch to the state before the merge began. -1. `*` What are pre-commit hooks and post-commit hooks, and what are they for? +1. `*` What are pre-commit hooks and post-commit hooks, and what are they for?
+- pre-commit hooks are run fast, they let you excute right before the commit to make sure about the tests run
+- post-commit hooks are right after the commit, it's used to notify about new change-information -1. `*` How do I change the last commit without adding a new commit? +1. `*` How do I change the last commit without adding a new commit? using `git commit --amend --no-edit` diff --git a/devops/02 - dockerfile/Dockerfile b/devops/02 - dockerfile/Dockerfile index f3258b32..b3c2a548 100644 --- a/devops/02 - dockerfile/Dockerfile +++ b/devops/02 - dockerfile/Dockerfile @@ -1,8 +1,13 @@ -FROM golang:1.15 +FROM golang:alpine AS builder WORKDIR /usr/src/app -COPY main.go . -COPY go.mod . -COPY .env . -RUN go get -d github.com/joho/godotenv +ARG PORT +COPY main.go go.mod ./ +RUN echo "PORT=$PORT" > .env +RUN go get -d github.com/joho/godotenv RUN CGO_ENABLED=0 GOOS=linux go build -o simple-webpage . + + +FROM alpine +WORKDIR /app +COPY --from=builder /usr/src/app /app CMD ["./simple-webpage"] diff --git a/devops/02 - dockerfile/README.md b/devops/02 - dockerfile/README.md index 7fddb4e8..3727c839 100644 --- a/devops/02 - dockerfile/README.md +++ b/devops/02 - dockerfile/README.md @@ -11,19 +11,32 @@ You need to optimize the Dockerfile by correcting or adding steps. ## Questions 1. What is Docker? Which technology is it based on? +- Docker is a software development platform, the idea of it is that you can develope and deploy your apps (codes) and package them into a unit called a container. +- Docker is written in Go, uses several features of the Linux kernel 2. Look at the Docker file – what would you change in it? + - I would use alpine, make all the copies at the same line and apply multi-stages 3. How do I pass variables to the Docker file when building and running the container? +- when building you use `docker build --build-arg =` and inside Docker file `ARG=${}` +- when running, `docker run -e =` 4. Why do we need multistage build ? +- To minimize the size of the final container, improve run time performance, allow for better organization of Docker ## Tasks -* Dockerfile - generate .env file inside Dockerfile, provide value of port at build step. +* Dockerfile - generate .env file inside Dockerfile, provide value of port at build step. Done in Dockerfile -* Multi-stage build – change the Dockerfile to make it multi-stage. Try to get the lowest container size. +* Multi-stage build – change the Dockerfile to make it multi-stage. Try to get the lowest container size. Done in Dockerfile -* Compare size of docker images with and without multistage build. +* Compare size of docker images with and without multistage build.
+without multistage build the size was 858MB but with the multistage build the size became 11.9MB
+Note: In addition, we could use FROM scratch instead of FROM alpine, it would decrease the size more (until 6.34MB) but at the same time, but alpine still have sh shell so you can still have more debugging stabilities and of course you can install packages because alpine has a package manager so I prefer to go with alpine
* Write down all commands which you have used. +- `docker build -t webserver` +- `docker images | grep webserver` you can here check the size +- `vime Dockerfile` +- `docker run -d -P -p 8080:8080 --name webserver webserver` +- `docker ps` diff --git a/devops/03 - docker-compose/README.md b/devops/03 - docker-compose/README.md index 2f2a4f23..8191fd90 100644 --- a/devops/03 - docker-compose/README.md +++ b/devops/03 - docker-compose/README.md @@ -25,23 +25,34 @@ Docker compose with 3 applications (frontend + backend + DB). ## Questions 1. What is the difference between Docker Compose and dockerfile? Why do I need Docker Compose? +- We need a Docker file to build an image and so it has the instructions for it +- We need Docker compose to describe running multiple Docker containers 2. How do I parameterize compose for different environments? +- Firstly we need `.env` file which must contains the variable we need to use in compose, then call them in the compose and it will automatically take thier value from the `.env` file +- Syntax: declare variable inside `.env` like this `VARIABLE=VALUE` , and in the compose `${VARIABLE}` 3. What types of entities are used in docker-compose and for what purpose? -4. `*` How to output application logs? +- version: specify the version of Docker compose +- services: configure docker container +- image: to pull a docker image +- volumes: to preserve data from outside containers generated by the running container. +- networks -4. `*` How to copy\upload a file from host machine to the container? +4. `*` How to output application logs? `docker-compose logs SERVICE` -5. `*` How to save file changes made inside the container? +4. `*` How to copy\upload a file from host machine to the container? `volumes: - /srcPath/srcFile:/dstPath/dstFile` + +5. `*` How to save file changes made inside the container? ## Tasks -* Docker-compose has a bug - investigate it! What would you improve? +* Docker-compose has a bug - investigate it! What would you improve? Personally I couldn't find any bug -* Docker-compose with an environment file. Create 2 different environment files for docker-compose +* Docker-compose with an environment file. Create 2 different environment files for docker-compose
+ Two different environment files were created (`.env` and `.env.dev`) the first one `.env` have some variables and the compose fill the values from `.env` automatically just by running `docker-compose up` while on the other file, we have the same variables(some of them with different values) and the compose fill the values only if we pass the `.env.dev` as argument using `docker-compose --env-file .env.dev up` * `*` Change the `docker-compose.yml` to run through dockerstack with code reuse (don't repeat yourself) diff --git a/devops/03 - docker-compose/example/.env b/devops/03 - docker-compose/example/.env new file mode 100644 index 00000000..7931bfd2 --- /dev/null +++ b/devops/03 - docker-compose/example/.env @@ -0,0 +1,4 @@ +DB_TAG=9.6.5 +NGINX_TAG=1.13.5 +PUB_PORT=8080 +NGINX_PORT=80 diff --git a/devops/03 - docker-compose/example/.env.dev b/devops/03 - docker-compose/example/.env.dev new file mode 100644 index 00000000..9787b5da --- /dev/null +++ b/devops/03 - docker-compose/example/.env.dev @@ -0,0 +1,4 @@ +DB_TAG=9.6.5 +NGINX_TAG=1.13.5 +PUB_PORT=8888 +NGINX_PORT=88 diff --git a/devops/03 - docker-compose/example/docker-compose.yml b/devops/03 - docker-compose/example/docker-compose.yml index 917b4f65..de171a84 100644 --- a/devops/03 - docker-compose/example/docker-compose.yml +++ b/devops/03 - docker-compose/example/docker-compose.yml @@ -1,7 +1,7 @@ version: '3' services: db: - image: "postgres:9.6.5" + image: "postgres:${DB_TAG}" volumes: - "dbdata:/var/lib/postgresql/data" env_file: @@ -20,14 +20,14 @@ services: depends_on: - db nginx: - image: "nginx:1.13.5" + image: "nginx:${NGINX_TAG}" ports: - - "8080:80" + - "${PUB_PORT}:${NGINX_PORT}" volumes: - ./conf.d:/etc/nginx/conf.d networks: - web_nw - depends_on: + depends_on: - flaskapp networks: db_nw: @@ -35,4 +35,4 @@ networks: web_nw: driver: bridge volumes: - dbdata: \ No newline at end of file + dbdata: diff --git a/devops/04 - bash/README.md b/devops/04 - bash/README.md index 3782c2ef..123a6415 100644 --- a/devops/04 - bash/README.md +++ b/devops/04 - bash/README.md @@ -2,10 +2,30 @@ * Docker on your local machine to launch testing environment ## Questions -* Mention the advantages and disadvantages of bash scripts -* What types of variables are used in bash? -* What is pipes in shell script and how to use it? -* How to show unique values of the second column from the CSV comma-separated file and sort results with the alphabet? +* Mention the advantages and disadvantages of bash scripts
+ + Advantages:
+ +1- Quick writting the scripts
+2- Quick start
+3- Interactive debugging
+ + Disadvantages:
+ +1- Sensitive syntax
+2- Execution speed is low in most cases
+ +* What types of variables are used in bash?
+ +1- System-Defined Variables
+2- User-Defined Variables + +* What is pipes in shell script and how to use it?
+ +The pipe character | is used to connect the output from one command to the input of another.
+You can make it do so by using the pipe character ‘|’. (ex: the commands in the next question) +* How to show unique values of the second column from the CSV comma-separated file and sort results with the alphabet?
+`cat filename.csv | cut -f2 -d , | sort | uniq` ## Task Create script which provide aggregated information about analysises and they datasets. Information about each analysis/deployment could be retrieved from `awscli.sh`: @@ -55,3 +75,57 @@ If you use OS different than macOS/Linux need to use Docker to launch your scrip ``` bash docker run -it -rm -v :/src -w /src --entrypoint bash cfmanteiga/alpine-bash-curl-jq -- ``` + +### Solution +The code solution is in the file `mycode.sh` you can run it using the command `./mycode.sh get_all_info` while `get_all_info` is the main function in my code
+the code has the input inside a list, and the output is: + + +``` json +{ + "analysises":{ + + "users": { + "datasetsCount":2 + "datasets":[ + { + "arn": "us-west-2epotsdtset/Zmlyc3REYXRhc2V0Cg==", + "name": "firstDataset" + } + { + "arn": "us-west-2epotsdtset/c2Vjb25kRGF0YXNldAo=", + "name": "secondDataset" + } + ] + } + + "billings": { + "datasetsCount":2 + "datasets":[ + { + "arn": "us-west-2epotsdtset/Zmlyc3REYXRhc2V0Cg==", + "name": "firstDataset" + } + { + "arn": "us-west-2epotsdtset/c2Vjb25kRGF0YXNldAo=", + "name": "secondDataset" + } + ] + } + + "usage reports": { + "datasetsCount":2 + "datasets":[ + { + "arn": "us-west-2epotsdtset/Zmlyc3REYXRhc2V0Cg==", + "name": "firstDataset" + } + { + "arn": "us-west-2epotsdtset/c2Vjb25kRGF0YXNldAo=", + "name": "secondDataset" + } + ] + } + } +} +``` diff --git a/devops/04 - bash/mycode.sh b/devops/04 - bash/mycode.sh new file mode 100644 index 00000000..ce10887f --- /dev/null +++ b/devops/04 - bash/mycode.sh @@ -0,0 +1,67 @@ +#! /bin/bash + +get_analysis() { + ID=$(echo $2 | base64) + cat << EOF +{ + "analysisId": "${ID}", + "datasetsIds":["$( echo firstDataset | base64 )","$( echo secondDataset | base64 )"] +} +EOF +} + +get_dataset() { + NAME=$(echo $2 | base64 -d) + cat << EOF +{ + "datasetId": "${2}", + "name": "${NAME}", + "datasetArn": "arn:us-west-2:reports:dataset/${2}" +} +EOF +} + +get_all_info() { + cat << EOF +{ + "analysises":{ +EOF + ANALYSIS_NAMES=("users" "billings" "usage reports") + for i in "${ANALYSIS_NAMES[@]}"; do + count=$(get_analysis $i | jq '.datasetsIds | length') + ID=$(get_analysis $i | jq '.datasetsIds' | tr '[]' ' ' | tr '","' ' ') + IDS=(${ID// / }) + cat << EOF + + "$i": { + "datasetsCount":$count + "datasets":[ +EOF +j=0 + + while [ $j -le $((count-1)) ] + do + ID1="${IDS[j]}" + datasetnam1=$(./awscli.sh get_dataset $ID1 | jq '.name' | tr -d '"') + ARN1=$(bash ./awscli.sh get_dataset $ID1 | jq '.datasetArn' | tr -d '"' | tr -d '"arn:') + datasetnam2=$(./awscli.sh get_dataset $ID2 | jq '.name' | tr -d '"') + cat << EOF + { + "arn": "$ARN1", + "name": "$datasetnam1" + } +EOF + j=$(( $j + 1 )) +done + cat << EOF + ] + } +EOF +done +cat << EOF + } +} +EOF +} + +$1 $@ diff --git a/devops/05 - cloud-ops/README.md b/devops/05 - cloud-ops/README.md index aa9d9773..b57d7eab 100644 --- a/devops/05 - cloud-ops/README.md +++ b/devops/05 - cloud-ops/README.md @@ -12,12 +12,12 @@ https://aws.amazon.com/free/?all-free-tier.sort-by=item.additionalFields.SortRan ## Tasks * Create an AWS account and protect the root user with MFA https://docs.aws.amazon.com/IAM/latest/UserGuide/id_root-user.html#id_root-user_manage_mfa - +Done * Create an EC2 instance, connect to it through SSH and install apache or nginx manually, terminate it then. - +Done * Create an EC2 instance, provision software (apache/nginx) using Cloudformation, validate the installation, finally delete the stack. Provide the resulting template as outcome of this task. - +In the file above `configuration.yaml` * (*) Given that we have a properly written Cloudformation template come up with an idea how we can create and update a cloudformation stack based on this template automatically. Try to implement it. @@ -25,6 +25,23 @@ https://aws.amazon.com/free/?all-free-tier.sort-by=item.additionalFields.SortRan 1. What the benefits of the cloud computing? +- Cost: computing eliminates the capital expense of buying hardware and software and setting up and running on-site data centers.. It all adds up very fast +- Speed: typically with just a few mouse clicks, giving businesses a lot of flexibility and taking the pressure off capacity planning +- Performance: The biggest cloud computing services run on a worldwide network of secure data centers, which are regularly upgraded to the latest generation of fast and efficient computing hardware. +- Security: Many cloud providers offer a broad set of policies, technologies and controls that strengthen your security posture overall + 2. What is the Infrastructure As Code? Pros/cons of it? +Infrastructure as Code is a way to automate the DevOps tasks (managing and provisioning infrastructure using configuration files) end to end instead of doing it manually. + +Advantages: +- It’s faster than manual processes for provisioned resources, databases, networking… +- Developer can deploy servers and applications according to business practicing and policies +- Alignment with DevOps + +Disadvantages: +- Require additional tools (which could cause additional errors) +- Places more responsibility to developers to write efficient code + + diff --git a/devops/05 - cloud-ops/configuration.yaml b/devops/05 - cloud-ops/configuration.yaml new file mode 100644 index 00000000..a9b55788 --- /dev/null +++ b/devops/05 - cloud-ops/configuration.yaml @@ -0,0 +1,54 @@ +Resources: + Ec2Instance: + Type: AWS::EC2::Instance + Metadata: + "AWS::CloudFormation::Init": + configSets: + setup: + - install_server + install_server: + packages: + yum: + httpd: [] + files: + "/var/www/html/index.html": + content: | + Hello world! + mode: 000644 + owner: root + group: root + services: + sysvinit: + httpd: + enabled: true + ensureRunning: true + Properties: + ImageId: ami-03d5c68bab01f3496 + InstanceType: t2.micro + SecurityGroups: !Ref InstanceSecurityGroup + KeyName: !Ref 'KeyName' + Tags: + - Key: Name + Value: Cloudformation + UserData: + # runs the cfn-init scripts + Fn::Base64: + !Sub | + #!/bin/bash -xe + yum update -y aws-cfn-bootstrap + /opt/aws/bin/cfn-init -v --stack ${AWS::StackName} --resource Instance --configsets setup --region ${AWS::Region} + /opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource Instance --region ${AWS::Region} + InstanceSecurityGroup: + Type: AWS::EC2::SecurityGroup + Properties: + GroupDescription: Enable ssh access. + SecurityGroupIngress: + - IpProtocol: tcp + FromPort: 22 + ToPort: 22 + CidrIp: 0.0.0.0/0 +Parameters: + KeyName: + Description: Name of an existing EC2 KeyPair. + Type: AWS::EC2::KeyPair::KeyName + ConstraintDescription: must be the name of an existing EC2 KeyPair.