We're a small team of 4 developers and 2 testers and I'm a team lead of the team. Developers do their tasks each in separate branch. Our stack is ASP.NET MVC, ASP.NET Core, Entity Framework 6, MSSQL, IIS, Windows Server. We also use Bitbucket, Jira software to store code and manage issues.
For example, there is a task "add an about window". A developer creates branch named "add-about-window" and put all the code there. Once the task is done, I do code review and in case all was good, I merge the branch into some accumulating branch let's name it "main". As a next step, I then manually deploy the updated "main" branch to test server with installed IIS, MSSQL. Once done I notify testers to test freshly uploaded app to make sure "add about window" is done correctly and works good. If testers find a bug, I have to revert the task branch merge from "main" branch and tell the developer to fix the bug in task's branch. Once the developer fixed it, I merge the branch into "main" branch again and ask testers to check again. In the end the task branch gets deleted.
This is really inconvenient, time consuming and frustrating. I have heard about git flow (maybe this is kind of what we have now).
Ideally, I would like this process to be as this:
Each developer still do work in separate branches.
Once a task is done and all the task code is in task branch I do code review.
Once code review is done and all found issues are fixed I just click "deploy"
There is a Docker image which contains IIS, MSSQL, Windows. It also with some base version of the application we work on, fully tested and stable. Let's say it's on a state of some date, like start of the year.
The Docker image is taken and a new container starts.
This Docker container gets fully initialized and then the code from a branch gets installed on the running container.
This container then has own domain name like "proj-100.branches.ourcompany.com" ("proj-100" is task's ID in Jira) which testers can go on and test.
This would definitely decrease time I spend on deployment and also will make the process more convenient and comfortable.
Can someone advice some resources I can learn about similar deployment models? Or maybe someone can share info on this. Any info will be very appreciated.
regardless of your stack, and before talking about the solutions, what you describe is the basic use case of any CI-CD process. all the exhausting manual steps you described, can be done with any CI tool.
now, let's consider what you already have, and talk about the steps for your desired solution - you're using bitbucket, which already gives you at least steps 1 and 2 - merging only approved PRs into master/main.
step 3 is where we start the CI automation process - you define a webhook upon certain actions in the bitbucket repo, which triggers a CI job/pipeline(can be a Jenkins server, gitlab-ci, or many other CI solutions). this way, you won't even need a "deploy" button, since the merging action can trigger the job, which can automatically run unit tests, integration tests(if you define them), build artifacts/docker-images and finally deploy.
step 4 needs some basic understanding of the docker containers design - a docker image is not a VM. it has its use cases and relevant scenarios, and more importantly an advised architecture guideline to follow.
to make it short, I'll only mention the principle of separation - each service should be in a separate container. it allows upscaling and easier debugging, and much more. which means - what you need is not a docker image that contains your entire system, but an orchestration of containers, each containing an independent software unit, with a clear responsibility. and here Kubernetes comes into play.
back to the CI job - after the PR merge, the job starts, running the pre-defined unit tests, building the container, and uploading to your registry.
moving to CD - depending on your process, after the updated and tested docker images are in your registry(could be artifactory/GitLab registry/docker registry...), the CD job can take any image it needs, and deploy them in your Kubernetes cluster. and that's it! the process is done.
A word of advice - if you don't have a professional DevOps team, or a good understanding of docker, CI-CD process, and Kubernetes, and if your dev team is small(and unfortunately it seems so) you may want to consider hiring a DevOps company to build the DevOps/CICD infrastructure for you, preferably with a completely managed DevOps solution and then do a handover. everything I wrote is just the guideline and basic points, to give you the big picture. good luck!
All the other answers are here great still I would like to add my piece of advice.
Recently I was also working on a product and we were three team members. It was a node.js project. If you are on AWS then you can use the AWS pipeline. This will detect pushes from a specific GitHub branch and the changes will get deployed to the server. The pipeline service has a build stage too. You can also configure slack notifications.
But you should have at least two environments production and dev to check if deployment is working properly on dev.
AWS also has services like AWS Code Commit and AWS Code Deploy.
This is just a basic solution. You don't actually need fancy software to set up ci/cd.
This kind of setup is usually supported by a CICD tool coupled with Kubernetes.
Either an on-premise one, like Jenkins+Kubernetes, or its Jenkins Kubernetes plugin, which runs dynamic agents in a Kubernetes cluster.
You can see an example in "How to Setup Jenkins Build Agents on Kubernetes Pods" by Bibin Wilson.
Or a Cloud one, like Bitbucket pipeline deploying a containerized application to Kubernetes
In both instances, the idea remains the same: create a ephemeral execution environment (a Docker container with the right components in it) for each pushed branch, in order to execute tests.
That way, said tests can take place before any merge between a feature branch and an integration branch like main.
If the tests pass, Jenkins itself could trigger an automatic merge (assuming the feature branch was rebased first on top of the target branch, main in your case)
We have similar process in our team.
We use gitlab-ci.
Hence there are some out of docker infrastructure (nginx with test stand dns),
we just create dev1, dev2 ... stands (5 stands for team of 10 developer and more than 6 microservices). For each devX stand and each microservice we have deploy to devX button in our CI-CD. And we just reserve in slack devX for feature Y on time of tests after deploy. Whan tests are done and bugs are fixed we merge to main branch and other feature brunch can be deployed and tested on devX stand.
As a next step, I then manually deploy the updated "main" branch to test server with installed IIS, MSSQL.
Once done I notify testers to test freshly uploaded app to make sure "add about window" is done correctly and works good.
If testers find a bug, I have to revert the task branch merge from "main" branch and tell the developer to fix the bug in task's branch.
If there are multiple environments then devs could deploy themselves into them. Even a single "dev" environment they can deploy to would greatly help. The devs should be able to deploy themselves and notify the testers without going through you.
That the deploy is "manual" is suspicious. How manual? Ideally it should just be a few button clicks. Sometimes you can even have it so that pushing to a branch does a deploy (through webhooks).
You should be able to deploy from branches besides main. What that means or looks like can vary a lot but the point is that if you're forcing everything there and having to revert when it doesn't work you're creating a lot of unneeded work. Ideally there should be some way to test locally. If there really can't be then you need to at least allow a way to deploy from any branch (or something like force pushing to a branch called 'dev' or something).
From another angle, unless the application gets horribly broken you don't necessarily need to rollback changes unless a release is coming soon. You can just have it fixed in another pull request.
All in all the main problem here sounds like there's only a single environment for testing, the process to deploy to it is far too manual, and the devs have no way to deploy to it themselves. This sort of thing is a massive bottle neck. Having a burdensome process to even begin to test things takes a big toll on everyone's morale -- which can be worse than the loss in velocity. You don't necesscarily need every dev to be able to spin up as many environments as they want at the push of a button but devs do need some autonomy to be able to test.
Having the application run in Docker containers can greatly help with running it locally as well as making the deployment process simpler. I've tried to stay away from specific product suggestions because this is more of a process problem it sounds like.
We normally merge feature branches to the development branch(Development branch is deployed to QA) and from there RELEASE tags are created subsequently followed by deployments to staging and production. All has been implemented through AWS codepipeline. Problem we are facing is that once RELEASE branch is created, we go into code freeze and we cant merge more into development branch i.e. get things into QA till production deployment is completed successfully(Think about scenario, if hotfix is needed in production, we need our development branch to be exactly what was deployed into production, prior to applying the hotfix). We are trying to figureout a way on how to avoid codefreeze while release is in progress. This is a high level description of our issue, would love to provide more details, if needed.
Thank you.
I think that it's good idea to build artifact and then deploy it across all environment, test, preprod, prod.
But according to Gitflow we use "release" branches for tests and we merge it to main, develop and delete release branch. So we have "release" artifact and we test it, but as I understand we deploy to prod artifact from tagged main branch. And for me it's strange.
What could be the objective reasons of this?
main <=> prod
The reason for this is simple, however, the usual name of the main branch is master. One needs to have an easy way to refer back to whatever prod contains, because, in the case of hotfixes, you want to branch out from prod, because the issue is reproducible there. It is another matter that there is usually a branch for hotfixes as well.
release branches
Basically, you may have many different things that are being developed at the same time. You probably want to create well-separated partitions of problem-spaces to define your tasks, each such partition would represent a release. So, if you are optimizing some business logic on the one hand and you are polishing the UI on the other hand, then you not necessarily know which one will be released first, so you will have some named branches for those. Having "release" branches is a convention for this. Now, when you are deploying a release to prod, you can merge master into your release branch and perform automatic and/or manual tests. When this is successful, your release branch is merged into your master branch.
Deleting a release branch
Once the work represented by a release branch is successfully completed, it makes sense to remove it after it was merged to avoid wasting storage space on things that are unlikely to change (because they were accepted). Note that if a problem arises with a release later on, you can always checkout the commit hash of the tagged commit that represents the release merge in order to see whether the problem you have seen was already manifesting when the release branch was released.
We are using visualstudio.com TFS to store the source code. We have DEV, STG and PROD branches. now I want to automate build and release to IIS server.
But it looks like to me that TFS compiles the code from the branch where I commit to, and that's the only build, after that I can install the same binary on all the servers.
But it doesn't seem to be ok, because what if we find a bug on the live code, so we need to fix it, but we already have new code in DEV, and we don't want to revert, and install the old code with the fix on the dev server?
What I think we should do is to merge the code from DEV to STG, from STG to PROD, but I couldn't find any module for that. And it looks strange, I would be surprised if I am the only person whats to do this, especially because it is doable with Jenkins.
thanks
I typically discourage automating merging of code between branches; merging should be a deliberate action. When someone expresses that desire, it's usually a sign of a problem with the branching model and deployment model they're using.
Code promotion branching (where you have one branch that corresponds to each environment, as in the scenario you described) is a bad practice because it encourages you to build different sets of binaries for each environment. You build something for a lower environment, test it, validate it, then totally disregard that testing and rebuild from source. That should terrify you, especially for production branches -- you have no idea if what you just built is going to work properly.
Current thinking is to minimize the number of branches you have, and instead isolate in-progress work behind feature toggles so that features that aren't ready for production can simply be disabled, but still allow deployments to take place. With sufficiently mature feature toggling practices and testing practices in place, you can actually eliminate branching entirely and work out of a single branch, promoting binaries to production whenever your automated and manual QA process deems the version they're testing is good.
Assuming you're using TFVC, if you want to maintain a code promotion branching strategy, then you'll need to maintain multiple builds and releases, one for each branch/environment. Typically, in this kind of scenario, I'd eliminate the stage branch entirely. Anything that goes to the Dev branch is built and deployed to Dev. Anything that goes into the Prod branch is built and follows a deployment pipeline from staging->production. Hotfixes can go directly into the prod branch and be merged backwards. There are tons of strategies for branching; you'll need to read up on the subject and design a branching and release strategy that works best for your team.
I would like to achieve the following setup in Travis CI.
Do a build whenever commits are pushed to dev or release branches only.
Disable builds whenever commits are pushed to any other branch apart from dev or release but build pull requests.
If a developer is really interested to know if his commits are good, then he should be able to kick start a build on Travis CI explicitly by choosing a branch/commit.
From reading the documentation on Travis CI and some blog posts, I see that I can achieve "1." and "2."
Does anyone know how to make "3." work?
Update-1:
The reason I want scenario "3." is because the developers in our team (or in general any other team) make several commits and push them even before they send out a pull request. Building for every single commit of a private branch even before it goes for a pull request is causing lot of requests to queue up in the Travis CI queue which unnecessarily blocks developers who really care to verify a particular commit to check if everything is good or not before sending out a pull request.
Having the following is just fine for us:
Build on every commit push to dev and release branches
Build on every commit pushed to a pull request
You can easily achieve 1 and 2 by whitelisting the branches you want to see push builds for:
branches:
only:
- dev
- release
For reference, see https://docs.travis-ci.com/user/customizing-the-build/#Whitelisting-or-blacklisting-branches.
You can achieve 3 only if your developers open a PR against one of the whitelisted branches.
I'd personally recommend to open a PR as early as possible (after the first commit), as it makes work in progress visible to everyone who is interested.